如何在 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 正则表达式替换命令中使用 unicode 字符?

Perl 和 Unix 如何以相同的顺序对 Unicode 字符串进行排序和排序?

w 是不是匹配 Unicode 标准中定义的所有字母数字字符?

如何在 Perl POD 派生的手册页中使用 Unicode 字符?