查找并替换字符内的弯引号 class

Find and replace curly quotes inside a character class

当我尝试查找字符 class 内的弯引号并将其替换为另一个字符时,我得到了奇怪的结果:

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

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

如果您使用 a 作为替换,您将得到 aaafooaaa。但这只是当弯引号位于字符 class 内时的问题。这有效:

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

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

谁能解释一下这是怎么回事?我仍然可以使用字符 class 作为弯引号吗?

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

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

但是在 en_US.UTF-8 ("US English encoded with UTF-8") 的正常语言环境中,我得到了想要的结果:

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

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

使用交替的版本可以工作,因为每个交替可以超过一个字符;即使 sed 仍然将‘和’视为三字符序列而不是单个字符,这种处理不会改变结果。

因此请确保您的文本编码区域设置正确,看看是否能解决您的问题。