0

当我尝试在字符类中查找并用另一个字符替换花引号时,我得到了奇怪的结果:

sed -E "s/[‘’]/'/g" in.txt > out.txt

in.txt:  ‘foo’
out.txt: '''foo'''

如果您a用作替代品,您将获得aaafooaaa. 但这只是当花引号在字符类中时才会出现的问题。这有效:

sed -E "s/(‘|’)/'/g" in.txt > out.txt

in.txt:  ‘foo’
out.txt: 'foo'

谁能解释这里发生了什么?我仍然可以对花引号使用字符类吗?

4

1 回答 1

2

您的字符串使用多字节编码,特别是 UTF-8;花括号每个是三个字节。但是您的sed实现将每个字节视为一个单独的字符。这可能是由于您的语言环境设置。我可以通过将我的语言环境设置为“C”(旧的默认 POSIX 语言环境,假定为 ASCII)来重现您的问题:

$ LC_ALL=C sed -E "s/[‘’]/'/g" <<<'‘foo’' # C locale, single-byte chars
'''foo'''

但是在我的 en_US.UTF-8(“用 UTF-8 编码的美国英语”)的正常语言环境中,我得到了想要的结果:

$ LC_ALL=en_US.UTF-8 sed -E "s/[‘’]/'/g" <<<'‘foo’' # UTF-8 locale, multibyte chars
'foo'

您运行它的方式sed不是[‘‘]四个字符的序列,而是八个字符的序列。因此,括号之间的六个字节中的每一个——或者至少是在这些字节中找到的四个唯一值中的每一个——都被认为是字符类的成员,并且每个匹配的字节都被撇号单独替换。这就是为什么您的三字节大引号每个都被三个撇号取代的原因。

使用交替的版本有效,因为每个交替可以是多个字符;即使sed仍然将 ' 和 ' 视为三个字符序列而不是单个字符,但该处理不会改变结果。

因此,请确保为您的文本编码正确设置您的语言环境,看看是否能解决您的问题。

于 2020-05-14T19:48:41.987 回答