【问题标题】:How do I match only fully-composed characters in a Unicode string in Perl?如何在 Perl 中仅匹配 Unicode 字符串中的完全组合字符?
【发布时间】:2010-09-17 05:53:13
【问题描述】:

我正在寻找一种仅匹配 Unicode 字符串中完全组成的字符的方法。

[:print:] 是否依赖于任何包含此字符类的正则表达式实现中的语言环境?例如,它会匹配日文字符“あ”,因为它不是控制字符,还是[:print:] 总是将是 ASCII 代码 0x20 到 0x7E?

是否有任何字符类(包括 Perl RE)可用于匹配控制字符以外的任何内容?如果 [:print:] 仅包含 ASCII 范围内的字符,我会假设 [:cntrl:] 也包含。

【问题讨论】:

    标签: regex perl unicode locale character-properties


    【解决方案1】:

    我认为您不需要或不需要语言环境,而是 Unicode。如果您已解码文本字符串,\w 将匹配任何语言的单词字符,\d 不仅匹配 0..9,而且匹配每个 Unicode 数字等。在正则表达式中,您可以使用 \p{PropertyName} 查询 Unicode 属性。对您来说特别有趣的可能是\p{Print}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(あ ご ご), "\x{3099}") {
          say encode_utf8 sprintf "%s $string", $string =~ /\A \X \z/msx ? 'ok' : 'nok';
      }
      

      测试数据是:一个普通字符、一个预组合字符、一个组合字符序列和一个组合字符(单独“不计算”,Unicode第3章的简化)。

      \X 替换为[[:print:]] 以查看Tanktalus 的答案在最后两种情况下会产生错误匹配。

      【讨论】:

        【解决方案3】:
        echo あ| perl -nle 'BEGIN{binmode STDIN,":utf8"} print"[$_]"; print /[[:print:]]/ ? "YES" : "NO"'
        

        这主要是有效的,尽管它会生成一个关于宽字符的警告。但它给了你一个想法:你必须确保你正在处理一个真正的 unicode 字符串(检查 utf8::is_utf8)。或者直接检查perlunicode - 整个主题仍然让我头晕目眩。

        【讨论】:

        • 您可以通过在命令行上提供选项 -CS 来摆脱丑陋的 BEGIN{binmode STDIN, ":utf8"} 杂种。
        • ... 这也会使警告消失,因为它以与 STDIN 相同的方式设置 STDOUT。
        • 如果 OP 正在编写一个模块来处理这个问题而不是一个独立的脚本,那么这可能不是一个选择。因此,我将留下我的解决方案以及您的解决方案,希望 OP 能够找出哪个更适合他/她的方案。谢谢:-)
        • 这种模式是错误的。 [[:print:]] 将匹配 "\x{3099}" 这不是一个完整的字符!请参阅我的答案以了解工作模式。
        【解决方案4】:

        您总是可以使用字符类[^[:cntrl:]] 来匹配非控制字符。

        【讨论】:

        • 这与 Unicode 控制字符不匹配(在我的环境设置和使用 Perl 中)。有用于更改文本方向等的 Unicode 控制字符。使用 [^[:ctrnl:]] 将匹配这些 Unicode,但不匹配 ASCII。
        【解决方案5】:

        是的,这些表达式取决于语言环境。

        【讨论】:

        • 您能否命名一个允许 [:print:] 尊重日语 UTF-8 语言环境/编码的环境和/或正则表达式实现?我在 Linux 中使用带有日文 UTF-8 语言环境/编码的 Perl,但它与日文字符不匹配。
        猜你喜欢
        • 1970-01-01
        • 2020-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-11
        相关资源
        最近更新 更多