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 scriptnws
  • 使用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()