sed 正则替换不支持 4 字节生僻字,怎么办

2018-07-03 00:22:20 +08:00
 helloiac

我要给一些古籍文本行加上包裹标签,如 p、h2 之类,是用 sed 做的;调试使用中发现,当行中包含 4 字节的生僻字时,.*这个匹配会失败,从而导致加包裹标签失败。

下面的测试是希望把问题说清楚,实际下面的 sed 命令是一个较大的脚本中一个长管道中的一环。测试文本中的 4 字节生僻字是“𢢼”。

请不吝赐教!

注释:赋值测试字符串给变量 a
qhel@qhel-vagrant MSYS /d/Documents/project/coding/guji
$ a="公乃密遣解𢢼、高祚等乘險夜襲"

注释:查看字符串长度
qhel@qhel-vagrant MSYS /d/Documents/project/coding/guji
$ echo ${#a}
15

注释:替换失败
qhel@qhel-vagrant MSYS /d/Documents/project/coding/guji
$ echo $a | sed "s/^[^#=;%:|-].*$/<p>&<\/p>/g";
公乃密遣解𢢼、高祚等乘險夜襲

=====
注释:去掉生僻字重新赋值给 b
qhel@qhel-vagrant MSYS /d/Documents/project/coding/guji
$ b="公乃密遣解、高祚等乘險夜襲"

qhel@qhel-vagrant MSYS /d/Documents/project/coding/guji
$ echo ${#b}
13

注释:替换成功
qhel@qhel-vagrant MSYS /d/Documents/project/coding/guji
$ echo $b | sed "s/^[^#=;%:|-].*$/<p>&<\/p>/g";
<p>公乃密遣解、高祚等乘險夜襲</p>

1479 次点击
所在节点    问与答
11 条回复
imn1
2018-07-03 01:59:10 +08:00
现在没开 linux 机器,测试不了
你试试把「𢢼」改成\u{2288c},试一下,注意需要花括号
OscarUsingChen
2018-07-03 04:23:56 +08:00
嗯,这边没问题。可能是你系统编码的问题。

a="公乃密遣解𢢼、高祚等乘險夜襲"

echo ${#a}
14

echo $a | sed "s/^[^#=;%:|-].*$/<p>&<\/p>/g";
<p>公乃密遣解𢢼、高祚等乘險夜襲</p>
kokutou
2018-07-03 07:18:00 +08:00
我记得当时 Windows 下替换不了,后来把源文本文件转成 utf-8,然后 cmd 里运行一下 chcp 65001 再运行 sed
应该是要文本编码和环境一样吧。
helloiac
2018-07-03 09:39:48 +08:00
@imn1 我是在 Windows 做的,因为文本不定,手动替换不太可行,后面我在 Linux 也测一下反馈结果
helloiac
2018-07-03 09:42:36 +08:00
@OscarUsingChen 我用的是 msys2 的环境,gbk ‘和 utf8 的终端环境都试过。你这用的是 Linux 吗?
helloiac
2018-07-03 09:46:31 +08:00
@kokutou 谢谢!我脚本处理的文本是 utf8 的,这个在终端的测试文本编码应该就是和终端环境有关了,也是 utf8。我没用 cmd,用的是 msys2 的 mintty。
helloiac
2018-07-03 10:44:26 +08:00
@imn1 试了一下是这样的,分别用复制粘贴和手动输入\u{2288c}:
```
qhel@qhel-vagrant MSYS /D/develop/vagrant/ubuntu/soushu
$ a="公乃密遣解𢢼▒、高祚等乘險夜襲"

qhel@qhel-vagrant MSYS /D/develop/vagrant/ubuntu/soushu
$ echo ${#a}
16

qhel@qhel-vagrant MSYS /D/develop/vagrant/ubuntu/soushu
$ echo $a | sed "s/^[^#=;%:|-].*$/<p>&<\/p>/g";
公乃密遣解𢢼▒、高祚等乘險夜襲

qhel@qhel-vagrant MSYS /D/develop/vagrant/ubuntu/soushu
$ a="公乃密遣解\u{2288c}、高祚等乘險夜襲"

qhel@qhel-vagrant MSYS /D/develop/vagrant/ubuntu/soushu
$ echo $a | sed "s/^[^#=;%:|-].*$/<p>&<\/p>/g";
<p>公乃密遣解\u{2288c}、高祚等乘險夜襲</p>
```
helloiac
2018-07-03 10:45:20 +08:00
@OscarUsingChen Linux 环境试过了,同样没问题。后面实在不行就麻烦一点,这个步骤搞到 Linux 执行。
imn1
2018-07-03 13:13:50 +08:00
这个问题的出现,主要是软件的 unicode 核心没有支持 FFFF 以后的字符( utf-8 四字节)
linux bash4.1 好像还未支持,但 4.2+就支持了,我以为你在 4.1 测试

你可以用「 unicode codepoint 」 google 一下,有绕弯的解决方案的
helloiac
2018-07-03 16:31:13 +08:00
@imn1 谢谢!我比较了本地 msys2 环境和 vagrant 中的 bash 版本,分别是:
GNU bash, version 4.4.19(2)-release (x86_64-pc-msys)
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

版本都高于 4.1,可能是 msys 版本的 bash 的问题。正在升级 bash 和 msys 的系统,升级完了用新版本 bash 和 zsh 都试一下。
helloiac
2018-07-03 17:05:45 +08:00
@imn1 升级 msys 的 bash 到最新版本后问题依旧,不过用 zsh 完美解决了问题。大谢!前面我还尝试过将本地的 LANG 变量修改为与 vagrant 中的 ubuntu 相同,不过没效果,没想到根本上是 shell 的问题。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/467637

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX