如何在 Perl 中仅匹配 Unicode 字符串中的完全组合字符?
Posted
技术标签:
【中文标题】如何在 Perl 中仅匹配 Unicode 字符串中的完全组合字符?【英文标题】:How do I match only fully-composed characters in a Unicode string in Perl? 【发布时间】:2010-09-17 05:53:13 【问题描述】:我正在寻找一种仅匹配 Unicode 字符串中完全组成的字符的方法。
[:print:]
是否依赖于任何包含此字符类的正则表达式实现中的语言环境?例如,它会匹配日文字符“あ”,因为它不是控制字符,还是[:print:]
总是将是 ASCII 代码 0x20 到 0x7E?
是否有任何字符类(包括 Perl RE)可用于匹配控制字符以外的任何内容?如果 [:print:]
仅包含 ASCII 范围内的字符,我会假设 [:cntrl:]
也包含。
【问题讨论】:
【参考方案1】:我认为您不需要或不需要语言环境,而是 Unicode。如果您已解码文本字符串,\w
将匹配任何语言的单词字符,\d
不仅匹配 0..9
,而且匹配每个 Unicode 数字等。在正则表达式中,您可以使用 \pPropertyName
查询 Unicode 属性。对您来说特别有趣的可能是\pPrint
。 Here's a list of all the available Unicode character properties.
我写了一个article about the basics and subtleties of Unicode and Perl,它应该让你知道该怎么做,perl 会将你的字符串识别为一个字符序列,而不仅仅是一个字节序列。
更新:使用 Unicode 时,您不会获得依赖于语言的行为,而是会采用合理的默认值,而不管语言如何。这可能是也可能不是您想要的,但是为了区分可打印/控制字符,我不明白您为什么需要依赖语言的行为。
【讨论】:
【参考方案2】:\X
匹配一个完整的字符(序列)。证明:
#!/usr/bin/env perl
use 5.010;
use utf8;
use Encode qw(encode_utf8);
for my $string (qw(あ ご ご), "\x3099")
say encode_utf8 sprintf "%s $string", $string =~ /\A \X \z/msx ? 'ok' : 'nok';
测试数据是:一个普通字符、一个预组合字符、一个组合字符序列和一个组合字符(单独“不计算”,Unicode第3章的简化)。
将\X
替换为[[:print:]]
以查看Tanktalus 的答案在最后两种情况下会产生错误匹配。
【讨论】:
【参考方案3】:echo あ| perl -nle 'BEGINbinmode STDIN,":utf8" print"[$_]"; print /[[:print:]]/ ? "YES" : "NO"'
这主要是有效的,尽管它会生成一个关于宽字符的警告。但它给了你一个想法:你必须确保你正在处理一个真正的 unicode 字符串(检查 utf8::is_utf8)。或者直接检查perlunicode - 整个主题仍然让我头晕目眩。
【讨论】:
您可以通过在命令行上提供选项 -CS 来摆脱丑陋的 BEGINbinmode STDIN, ":utf8" 杂种。 ... 这也会使警告消失,因为它以与 STDIN 相同的方式设置 STDOUT。 如果 OP 正在编写一个模块来处理这个问题而不是一个独立的脚本,那么这可能不是一个选择。因此,我将留下我的解决方案以及您的解决方案,希望 OP 能够找出哪个更适合他/她的方案。谢谢:-) 这种模式是错误的。 [[:print:]] 将匹配 "\x3099" 这不是一个完整的字符!请参阅我的答案以了解工作模式。【参考方案4】:您总是可以使用字符类[^[:cntrl:]]
来匹配非控制字符。
【讨论】:
这与 Unicode 控制字符不匹配(在我的环境设置和使用 Perl 中)。有用于更改文本方向等的 Unicode 控制字符。使用 [^[:ctrnl:]] 将匹配这些 Unicode,但不匹配 ASCII。【参考方案5】:是的,这些表达式取决于语言环境。
【讨论】:
您能否命名一个允许 [:print:] 尊重日语 UTF-8 语言环境/编码的环境和/或正则表达式实现?我在 Linux 中使用带有日文 UTF-8 语言环境/编码的 Perl,但它与日文字符不匹配。以上是关于如何在 Perl 中仅匹配 Unicode 字符串中的完全组合字符?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Perl 中枚举所有 Unicode 规范等效序列?
如何在 perl 正则表达式替换命令中使用 unicode 字符?
Perl 和 Unix 如何以相同的顺序对 Unicode 字符串进行排序和排序?