我需要将它们全部替换为普通的"space"字符。
使用 Perl 很容易:
perl -CSDA -plE 's/\s/ /g' file
但是正如@mklement0在评论中正确指出的那样,它也将匹配\t
(制表符)。如果这是个问题,您可以使用:
perl -CSDA -plE 's/[^\S\t]/ /g'
演示:
X X
以上内容包括:
U+00058 X LATIN CAPITAL LETTER X
U+01680 OGHAM SPACE MARK
U+02002 EN SPACE
U+02003 EM SPACE
U+02004 THREE-PER-EM SPACE
U+02005 FOUR-PER-EM SPACE
U+02006 SIX-PER-EM SPACE
U+02007 FIGURE SPACE
U+02008 PUNCTUATION SPACE
U+02009 THIN SPACE
U+0200A HAIR SPACE
U+0202F NARROW NO-BREAK SPACE
U+0205F MEDIUM MATHEMATICAL SPACE
U+03000 IDEOGRAPHIC SPACE
U+00058 X LATIN CAPITAL LETTER X
使用:
perl -CSDA -plE 's/\s/_/g' <<<"X X"
注意,对于演示替换为下划线,打印出来
X_____________X
同时,也可以使用纯bash实现。
LC_ALL=en_US.UTF-8 spaces=$(printf "%b" "\U00A0\U1680\U180E\U2000\U2001\U2002\U2003\U2004\U2005\U2006\U2007\U2008\U2009\U200A\U200B\U202F\U205F\U3000\UFEFF")
while read -r line; do
echo "${line//[$spaces]/ }"
done
LC_ALL=en_US.UTF-8
只有在你的默认语言环境不是 UTF-8
时才需要设置。(如果你正在处理 utf8 文本,则应该使用它):)
str="X X"
echo "${str//[$spaces]/_}"
再次打印:
X_____________X
同样地,使用sed
- 准备与上述相同的变量$spaces
并使用以下命令:
sed "s/[$spaces]/ /g" file
编辑 - 因为一些奇怪的复制/粘贴(或本地化)问题:
xxd -ps <<<"$spaces"
展示
c2a0e19a80e1a08ee28080e28081e28082e28083e28084e28085e28086e2
8087e28088e28089e2808ae2808be280afe2819fe38080efbbbf0a
md5
摘要(两个不同的程序)
md5sum <<<"$spaces"
LC_ALL=C md5 <<<"$spaces"
打印相同的md5
35cf5e1d7a5f512031d18f3d2ec6612f -
35cf5e1d7a5f512031d18f3d2ec6612f
可以通过它们的Unicode来识别字符,但是sed 's/[[:space:]]\+/\ /g'
无法实现这一点。
通过改编另一个SO答案,我们列出所有的Unicode并将它们保存在一个变量中,然后使用sed进行替换(注意使用-i.bak
,我们还将保存原始文件的副本)。
CHARS=$(printf "%b" "\U00A0\U1680\U180E\U2000\U2001\U2002\U2003\U2004\U2005\U2006\U2007\U2008\U2009\U200A\U200B\U202F\U205F\U3000\UFEFF")
sed -i.bak 's/['"$CHARS"']/ /g' /tmp/file_to_edit.txt
\U...
转义需要Bash 4.x。
如果您的sed
(a)遵循区域设置的UTF-8字符映射,并且(b)该字符映射是最新的(例如,Ubuntu 16.04不是这种情况),那么s/[[:space:]]/ /g'
应该可以工作-它也会替换制表符。
\+
并不是必要的,更重要的是,它不可移植。
小问题:printf "%b" '...'
可以改为printf '...'
-不需要%b
的绕路; 最好不要使用全大写的Shell变量名称。 - mklement0nws
(标准化空白),这是一个简化任务的实用程序(由我提供):nws --ascii file # convert non-ASCII whitespace and punctuation to ASCII
nws --ascii -i file # update file in place
< p > nws
的 --ascii
模式:
将(非ASCII)Unicode 空格(例如不间断空格(
))和标点符号(例如弯引号(“”
),短横线(–
),...)转换为最接近的 ASCII 等效物。
同时保留其他任何 Unicode 字符。
此模式对于已使用印刷引号、破折号等格式进行显示的源代码示例非常有帮助,这通常会使编译器/解释器无法处理代码。
nws
(适用于Linux和macOS)从npm registry。请注意:即使您不使用Node.js,其包管理器npm
也可以跨平台工作并且易于安装;尝试curl -L https://git.io/n-install | bash
。已安装Node.js,请按照以下步骤进行安装:[sudo] npm install nws-cli -g
注意:
bash
的Unix平台)bash
脚本并将其命名为nws
。chmod +x nws
将其变为可执行文件。$PATH
中的文件夹,例如在(macOS)中的/usr/local/bin
或(Linux)中的/usr/bin
。[:space:]
和[:blank:]
以及非ASCII Unicode空格在基于UTF-8的语言环境中,符合POSIX标准的工具应该使POSIX字符类[:space:]
和[:blank:]
匹配(非ASCII)Unicode空格。
这依赖于区域设置字符映射正确分类基于 POSIX规定的字符分类的Unicode字符,这些直接对应于模式和正则表达式中可用的字符类,如[:space:]
。
有两个陷阱:
Unicode 是一个不断发展的标准(截至本文版本为第9版);你所使用的 UTF-8 字符映射表可能已经过时。
Ubuntu 16.04
上,以下字符未被正确分类,因此无法匹配 [:space:]
/ [:blank:]
:工具应该使用活动区域设置的字符映射表 - 但有令人遗憾的例外 - 以下工具不支持 Unicode(可能还有更多):
在 GNU 工具中(截至 coreutils v8.27):
cut
、tr
Mawk,例如 Ubuntu 默认的 awk
实现。
在 BSD/macOS 工具中(截至 macOS 10.12):
awk
sed
命令应该可以工作,但请注意[:space:]
也匹配制表符,因此也会将它们替换为一个空格:sed 's/[[:space:]]/ /g' file
FILENAME = 'File.txt'
OUTPUTNAME = 'Fixed.txt'
f = open(FILENAME, 'r+', encoding='utf8')
o = open(OUTPUTNAME, 'w+', encoding='utf8')
for line in f:
for ch in line:
if ch == '\u2003':
ch = ' '
o.write(ch)
else:
o.write(ch)
o.close()
f.close()
spaces=$(python -c 'print u"\u0020\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200b\u202f\u205f\u3000\ufeff".encode("utf8")')
就可以正常工作。 - Kuzekomd5sum <<<"$spaces"
的结果应该打印出35cf5e1d7a5f512031d18f3d2ec6612f
,如果不是,则说明你的复制和粘贴有误。 - clt60printf
本身。你需要有xx_xx.UTF-8
本地化设置,例如en_US.utf8
。已编辑答案。 - clt60\U...
转义需要Bash 4.x;关于perl
解决方案:\s
也会匹配_tab_,并将其替换为单个空格可能不是所需的。一个小问题:printf "%b" '...'
可以直接写成printf '...'
- 不需要%b
这一步骤。 - mklement0\t
。关于%b
也是对的,但我个人喜欢显式格式。;) 感谢您的评论。添加关于\t
的编辑。 - clt60