bash - 删除所有 Unicode Spaces 并替换为 Normal Space
bash - Remove all Unicode Spaces and replace with Normal Space
我有一个包含很多文本的文件,其中混合了特殊的 space 字符,
这些是 Unicode Spaces
我需要用 普通 "space" 字符替换它们。
可以通过 unicode 来识别字符,不幸的是 sed 's/[[:space:]]\+/\ /g'
无法做到这一点。
通过修改另一个 SO answer,我们列出所有的 unicodes 并将它们保存在一个变量中,然后使用 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
易于使用 perl:
perl -CSDA -plE 's/\s/ /g' file
但是正如@mklement0 在评论中正确地说的那样,它也会匹配 \t
(TAB)。如果这是问题,您可以使用
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
仅当您的默认语言环境不是 UTF-8
时才需要 LC_ALL=en_US.UTF-8
。 (你应该有,如果你使用 utf8 文本):)
演示:
str="X X"
echo "${str//[$spaces]/_}"
再次打印:
X_____________X
同样使用 sed
- 如上所述准备变量 $spaces
并使用:
sed "s/[$spaces]/ /g" file
编辑 - 因为一些奇怪的copy/paste(或语言环境)问题:
xxd -ps <<<"$spaces"
显示
c2a0e19a80e1a08ee28080e28081e28082e28083e28084e28085e28086e2
8087e28088e28089e2808ae2808be280afe2819fe38080efbbbf0a
md5
摘要(两个不同的程序)
md5sum <<<"$spaces"
LC_ALL=C md5 <<<"$spaces"
打印相同的 md5
35cf5e1d7a5f512031d18f3d2ec6612f -
35cf5e1d7a5f512031d18f3d2ec6612f
如果您反复面临此任务,请考虑安装 nws
(normalize whitespace),一个简化任务的实用程序(我的):
nws --ascii file # convert non-ASCII whitespace and punctuation to ASCII
nws --ascii -i file # update file in place
nws
的--ascii
模式:
音译(非 ASCII)Unicode 白色 space(例如不间断 space (
))和标点符号(例如弯引号(“”
), en dash (–
), ... ) 到最接近的 ASCII 等价物
同时保留任何其他 Unicode 字符。
此模式对源代码示例很有帮助,这些示例已被格式化为使用印刷引号、em 破折号等显示,这通常会使代码难以理解 compilers/interpreters。
从 npm registry(Linux 和 macOS)安装 nws
注意:即使您不使用Node.js、npm
,它的包管理器也可以跨平台工作并且易于安装;尝试
curl -L https://git.io/n-install | bash
安装了Node.js,安装如下:
[sudo] npm install nws-cli -g
注:
- 是否需要
sudo
取决于您的安装方式 Node.js 以及您是否有 changed permissions later;如果出现 EACCES
错误,请使用 sudo
. 重试
-g
确保 global installation 并且需要将 nws-cli
放入系统的 $PATH
。
手动安装(任何具有 bash
的 Unix 平台)
- 下载 this
bash
script 为 nws
。
- 使用
chmod +x nws
使其可执行。
- 将其移动或符号链接到您
$PATH
中的文件夹,例如 /usr/local/bin
(macOS) 或 /usr/bin
(Linux)。
可选阅读:POSIX字符classes [:space:]
and [:blank:]
and non-ASCII Unicode whitespace
在基于 UTF-8 的语言环境中,POSIX 兼容实用程序 应该 生成 POSIX 字符 class [:space:]
和 [:blank:]
匹配(非 ASCII)Unicode whitespace.
这依赖于locale charmap在POSIX-mandated character classifications基础上对Unicode字符的正确class化,直接对应字符class如[:space:]
,可用在模式和正则表达式中。
有两个陷阱:
Unicode 是一个不断发展的标准(撰写本文时为第 9 版); 您平台的 UTF-8 charmap 可能不是最新的。
- 例如,在
Ubuntu 16.04
上,以下字符未正确 class 化,因此与 [:space:]
/ [:blank:]
不匹配:
不间断space,图形space,窄不间断space,下一行
实用程序应该使用活动语言环境的字符映射——但也有令人遗憾的例外——以下实用程序不支持 Unicode(可能还有更多):
在 GNU 实用程序中(从 coreutils v8.27 开始):
cut
, tr
Mawk,例如 Ubuntu 上默认的 awk
实现。
在 BSD/macOS 个实用程序中(从 macOS 10.12 开始):
awk
因此,在具有当前 UTF-8 字符映射的平台上,以下 sed
命令应该有效,但请注意 [:space:]
也匹配 tab 字符,因此也用单个 space 替换它们:
sed 's/[[:space:]]/ /g' file
如果你使用 python3 这对我有用,它的临时代码确实有效。
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()
我有一个包含很多文本的文件,其中混合了特殊的 space 字符, 这些是 Unicode Spaces
我需要用 普通 "space" 字符替换它们。
可以通过 unicode 来识别字符,不幸的是 sed 's/[[:space:]]\+/\ /g'
无法做到这一点。
通过修改另一个 SO answer,我们列出所有的 unicodes 并将它们保存在一个变量中,然后使用 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
易于使用 perl:
perl -CSDA -plE 's/\s/ /g' file
但是正如@mklement0 在评论中正确地说的那样,它也会匹配 \t
(TAB)。如果这是问题,您可以使用
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
仅当您的默认语言环境不是 UTF-8
时才需要 LC_ALL=en_US.UTF-8
。 (你应该有,如果你使用 utf8 文本):)
演示:
str="X X"
echo "${str//[$spaces]/_}"
再次打印:
X_____________X
同样使用 sed
- 如上所述准备变量 $spaces
并使用:
sed "s/[$spaces]/ /g" file
编辑 - 因为一些奇怪的copy/paste(或语言环境)问题:
xxd -ps <<<"$spaces"
显示
c2a0e19a80e1a08ee28080e28081e28082e28083e28084e28085e28086e2
8087e28088e28089e2808ae2808be280afe2819fe38080efbbbf0a
md5
摘要(两个不同的程序)
md5sum <<<"$spaces"
LC_ALL=C md5 <<<"$spaces"
打印相同的 md5
35cf5e1d7a5f512031d18f3d2ec6612f -
35cf5e1d7a5f512031d18f3d2ec6612f
如果您反复面临此任务,请考虑安装 nws
(normalize whitespace),一个简化任务的实用程序(我的):
nws --ascii file # convert non-ASCII whitespace and punctuation to ASCII
nws --ascii -i file # update file in place
nws
的--ascii
模式:
音译(非 ASCII)Unicode 白色 space(例如不间断 space (
“”
), en dash (–
), ... ) 到最接近的 ASCII 等价物同时保留任何其他 Unicode 字符。
此模式对源代码示例很有帮助,这些示例已被格式化为使用印刷引号、em 破折号等显示,这通常会使代码难以理解 compilers/interpreters。
从 npm registry(Linux 和 macOS)安装 nws
注意:即使您不使用Node.js、npm
,它的包管理器也可以跨平台工作并且易于安装;尝试
curl -L https://git.io/n-install | bash
安装了Node.js,安装如下:
[sudo] npm install nws-cli -g
注:
- 是否需要
sudo
取决于您的安装方式 Node.js 以及您是否有 changed permissions later;如果出现EACCES
错误,请使用sudo
. 重试
-g
确保 global installation 并且需要将nws-cli
放入系统的$PATH
。
手动安装(任何具有 bash
的 Unix 平台)
- 下载 this
bash
script 为nws
。 - 使用
chmod +x nws
使其可执行。 - 将其移动或符号链接到您
$PATH
中的文件夹,例如/usr/local/bin
(macOS) 或/usr/bin
(Linux)。
可选阅读:POSIX字符classes [:space:]
and [:blank:]
and non-ASCII Unicode whitespace
在基于 UTF-8 的语言环境中,POSIX 兼容实用程序 应该 生成 POSIX 字符 class [:space:]
和 [:blank:]
匹配(非 ASCII)Unicode whitespace.
这依赖于locale charmap在POSIX-mandated character classifications基础上对Unicode字符的正确class化,直接对应字符class如[:space:]
,可用在模式和正则表达式中。
有两个陷阱:
Unicode 是一个不断发展的标准(撰写本文时为第 9 版); 您平台的 UTF-8 charmap 可能不是最新的。
- 例如,在
Ubuntu 16.04
上,以下字符未正确 class 化,因此与[:space:]
/[:blank:]
不匹配:
不间断space,图形space,窄不间断space,下一行
- 例如,在
实用程序应该使用活动语言环境的字符映射——但也有令人遗憾的例外——以下实用程序不支持 Unicode(可能还有更多):
在 GNU 实用程序中(从 coreutils v8.27 开始):
cut
,tr
Mawk,例如 Ubuntu 上默认的
awk
实现。在 BSD/macOS 个实用程序中(从 macOS 10.12 开始):
awk
因此,在具有当前 UTF-8 字符映射的平台上,以下 sed
命令应该有效,但请注意 [:space:]
也匹配 tab 字符,因此也用单个 space 替换它们:
sed 's/[[:space:]]/ /g' file
如果你使用 python3 这对我有用,它的临时代码确实有效。
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()