提问人:geekley 提问时间:12/15/2021 最后编辑:lordadmirageekley 更新时间:10/1/2022 访问量:527
如何在 perl 正则表达式替换命令中使用 unicode 字符?
How can I use unicode characters in perl regex substitution command?
问:
这在使用 unicode 字符时不起作用(在 Ubuntu bash 中):
$ perl -pC -e's/[à]/a/gu' <<< 'à'
à
$ perl -pC -e's/[b]/a/gu' <<< 'b'
a
尽管它似乎受到 PCRE 的支持(至少根据 regex101)。
我做错了什么?我在 perl 命令中是否缺少一些标志?
这在 javascript 中“有效”,所以如果我能在命令行中想出一个简单的单行代码,我会使用 node ......但我仍然想知道为什么 perl 命令不起作用。
对于上下文:
我正在尝试使用像 、 等替换来发音字典文件(即删除单词列表的重音等),这样我就可以用它来使拼写检查重音不敏感(例如在 IntelliJ Idea 中)。/[àâáãä]/a/g
/[òôóõö]/o/g
基本上,这些是制作“asciified”额外词典的步骤:
- 下载该语言的 .dic 文件(所有单词的列表)
- 使用 grep 过滤包含非 ASCII / 可替换字符的单词
- 连续使用正则表达式替换使单词不区分重音
- 在 IDE 中导入 asciified 的 .dic 文件(除了标准语言词典之外)
答:
所有这些的一种实用方法是使用 Text::Unidecode
perl -C -MText::Unidecode -pe'unidecode($_)' <<< 'à'
指纹。该模块将 Unicode 文本音译为纯 ASCII。a
另一种方法:使用 Unicode::Normalize 分解字符(“normalize”),以便将字符及其变音符号(组合重音)分隔成它们自己的代码点,同时它们仍然形成一个有效的字素,然后用简单的正则表达式删除变音符号(或)。\p{NonspacingMark}
\p{Mn}
这两种方式都会有例外和边缘情况,但我认为它可能只是您需要的。
对于包含特定(文字)字符的代码,需要通过带有命令行标志或带有命令行标志的 utf8 编译指示告诉 Perl 程序源代码是 UTF-8use utf8;
-Mutf8
perl -C -Mutf8 -pe's/[à]/a/g' <<< 'à'
评论
sudo apt install libtext-unidecode-perl
您需要添加以告诉 Perl 程序是使用 UTF-8 而不是 ASCII 编码的。-Mutf8
$ perl -pC -Mutf8 -e's/[à]/a/gu' <<< 'à'
a
评论
-Mutf8
是我一直在寻找的。谢谢!+1
以下是我如何实现步骤 2 和 3。
例如,可以在这些词典中使用它(尽管我没有在每种语言上都对其进行测试)。
asciify-dic
#!/usr/bin/env bash
#License: "Zero-Clause BSD" <https://opensource.org/licenses/0BSD>
if [[ "$1" == "--help" ]]; then
echo "Usage: $(basename "$0") INPUT_FILE > OUTPUT_FILE"
echo "Asciify a .dic file (list of dictionary words)."
echo ""
echo "Generates a file with ASCII-only versions of the words that have non-ASCII chars."
echo "These additional words can be used to make spell-checking accent-insensitive."
echo "Comment lines beginning with % are left unchanged."
exit
fi
# Filter words containing non-ascii characters, except in comments
grep -P '^\%|[^\x00-\x7F]' $1 |
# Make words accent-insensitive, except in comments
perl -C -MText::Unidecode -pe'next if /^\s*%/;unidecode($_)' |
# Remove duplicate lines, except in comments
awk '/^\s*%/||!seen[$0]++'
用法示例:
asciify-dic $DIC_NAME.dic > $DIC_NAME-asciified.dic
评论
uniq
)
uniq
awk
awk
简短的回答是添加到您的命令行。-Mutf8
如果你不确定Perl是如何解释你在命令行上写的内容的,你可以让它用核心函数把它吐回给你,或者用 .这将很快说明您的问题。(将“à”字符括在括号中在这里没有任何作用。B::perlstring()
B::Deparse
$ perl -MO=Deparse -pC -e 's/à/a/gu' <<< 'à'
LINE: while (defined($_ = <ARGV>)) {
s/\303\240/a/gu;
}
continue {
die "-p destination: $!\n" unless print $_;
}
-e syntax OK
看看你的替换是如何有 2 个字符的?
然后,您可以立即看到如何解决您的问题。use utf8
$ perl -MO=Deparse -Mutf8 -pC -e 's/à/a/gu' <<< 'à'
use utf8;
LINE: while (defined($_ = <ARGV>)) {
s/\340/a/gu;
}
continue {
die "-p destination: $!\n" unless print $_;
}
-e syntax OK
你可以用它来确保Perl正在接收你认为的输入。perlstring()
$ perl -p -MB -E 'say B::perlstring($_)' <<< 'à'
"\303\240\n"
à
$ perl -pC -MB -E 'say B::perlstring($_)' <<< 'à'
"\x{e0}\n"
à
您可以看到,如果没有 Perl,则接收 2 个分解字符。-C
根据具体情况,Perl 将字符转储为八进制代码 () 或十六进制代码 ()。请注意,您始终可以将命令行中的原始 unicode 字符替换为转义码版本。这是一个很好的方法,可以明确说明否则会模棱两可的内容。\340
\xE0
$ perl -pC -e 's/[\xE0]/a/gu' <<< 'à'
a
如果您不想记住 UTF8 模式,则可以将这些选项推入环境变量或创建 shell 别名。谨防将其全球化!PERL5OPT
$ export PERL5OPT='-C -Mutf8'
$ perl -MO=Deparse -p -e 's/à/a/gu' <<< 'à'
use utf8;
LINE: while (defined($_ = <ARGV>)) {
s/\340/a/gu;
}
continue {
die "-p destination: $!\n" unless print $_;
}
-e syntax OK
$ perl -MB -p -E 'say B::perlstring($_)' <<< 'à'
"\x{e0}\n"
à
或作为 shell 别名。
alias uperl='perl -C -Mutf8'
有关如何将 Swiss Army Chainsaw 命令行的更多信息,请参见 perlrun。
另请参见 B::D eparse。
评论
bind 'set input-meta on'; bind 'set output-meta on'