【问题标题】:Should I use \d or [0-9] to match digits in a Perl regex?我应该使用 \d 还是 [0-9] 来匹配 Perl 正则表达式中的数字?
【发布时间】:2010-10-27 19:15:06
【问题描述】:

在过去几周阅读了许多问题/答案后,我看到在 perl 正则表达式中使用 \d 被评论为不正确。在 perl 的更高版本中\d[0-9] 不同,因为\d 将代表任何具有数字属性的Unicode 字符,而[0-9] 代表字符'0'、'1'、 '2', ..., '9'。

我很欣赏在某些情况下[0-9] 将是正确的使用方式,而在其他情况下\d 将是正确的。我想知道哪些人认为使用正确的默认值?

我个人觉得\d 表示法非常简洁和富有表现力,而相比之下[0-9] 则有些麻烦。但我很少有编写多语言代码的经验,或者更确切地说是为不适合 ASCII 字符范围的语言编写代码,因此可能是幼稚的。

我注意到了

$find /System/Library/Perl/5.8.8/ -name \*pm | xargs grep '\\d' | wc -l
  298
$find /System/Library/Perl/5.8.8/ -name \*pm | xargs grep '\[0-9\]' | wc -l
  26

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    在我看来,使用\d 非常危险,在语言中这是一个糟糕的设计决策,因为在大多数情况下你想要[0-9]。霍夫曼编码将规定使用\d 表示ASCII 数字。

    之前的大多数海报已经强调了为什么你应该使用[0-9],所以让我再给你一点数据:

    • 如果我正确阅读了 unicode 图表,“۷۰”是一个数字(印度语中的 70,不要相信我的话)。

    • 试试这个:

      $ perl -le '$one = chr 0xFF11; print "$one + 1 = ", $one+1;'
      1 + 1 = 1
      
    • 这里是有效数字的部分列表(可能会或可能不会在浏览器中正确显示,具体取决于您使用的字体),对于每个数字,只有第一个在进行算术运算时被解释为数字Perl,如上图:

       ZERO:  0٠۰߀०০੦૦୦௦౦೦൦๐໐0
       ONE:   1١۱߁१১੧૧୧௧౧೧൧๑໑1
       TWO:   2٢۲߂२২੨૨୨௨౨೨൨๒໒2
       THREE: 3٣۳߃३৩੩૩୩௩౩೩൩๓໓3
       FOUR:  4٤۴߄४৪੪૪୪௪౪೪൪๔໔4
       FIVE:  5٥۵߅५৫੫૫୫௫౫೫൫๕໕5
       SIX:   6٦۶߆६৬੬૬୬௬౬೬൬๖໖6
       SEVEN: 7٧۷߇७৭੭૭୭௭౭೭൭๗໗7
       EIGHT: 8٨۸߈८৮੮૮୮௮౮೮൮๘໘8
       NINE:  9٩۹߉९৯੯૯୯௯౯೯൯๙໙9��
      

    你还不服气吗?

    【讨论】:

    • +1 为该列表!我开始想知道还有哪些其他数字字符。
    • 如果 Perl 到目前为止已经接受了 UNICODE,那么它似乎应该继续处理所有的数字。当然,这种方式是疯狂的,但疯狂不是所有 Perl 程序员的命运 ;-) 吗?
    • 还有更多字符,但我只包括了我可以在我的系统上显示的字符。我使用了来自unicode.org/Public/UNIDATA/UnicodeData.txt 的 unicode 数据,并从那里提取了字符信息。
    • @nickf 在我目前的计数中,有 61 组数字,请参阅我的答案中的模块链接以获取列表。
    • @Beano 我不是说不要使用 \d;我是说当你的意思是 [0-9] 时不要使用 \d。当您的意思是 [ ] 时,它类似于不使用 \s。问题归结为你介意匹配⑤和5吗?
    【解决方案2】:

    为了最大程度的安全,我建议您在任何时候不打算匹配所有 unicode 定义的数字时使用 [0-9]

    根据 perldoc perluniintro,Perl 不支持使用除 [0-9] 以外的数字作为数字,所以如果以下都为真,我肯定会使用 [0-9]

    1. 您希望将结果用作数字(例如对其执行数学运算或将其存储在仅接受正确数字的位置(例如数据库中的 INT 列))。

    2. 非数字 [^0-9] 可能会以正则表达式匹配它们的方式出现在数据中。 (请注意,对于不受信任/敌对的输入,这应该始终被认为是正确的。)

    如果其中任何一个是错误的,那么很少有理由专门使用\d(你可能会知道什么时候是这种情况),如果你're 尝试匹配所有 unicode 定义的数字,你肯定想使用\d

    【讨论】:

    • \d 如果应用于 Unicode 字符串,确实可以匹配超过 10 个不同的字符。
    【解决方案3】:

    根据perlreref,“\d”可以识别区域设置和 Unicode。

    但是,如果您使用的代码集不是 Unicode,那么您无需担心 Unicode 数字,并且如果您使用的代码集类似于 Latin-1(ISO 8859-1 或 8859- 15),那么语言环境意识也不会伤害您,因为代码集不包含任何其他数字字符。

    因此,对于很多人来说,大多数时候,您可以毫无顾虑地使用“\d”。但是,如果 Unicode 数据是您工作的一部分,那么您需要更仔细地考虑您的目标。

    【讨论】:

      【解决方案4】:

      就像从轨道上攻击站点一样,[0-9] 是唯一可以确定的方法。是的,它很丑。是的,让\d 成为 UNICODE 和区域设置的选择是愚蠢的。但这是我们的床,我们必须躺在上面。

      至于那些低头在沙子里说这不会影响他们今天使用的字符集的人,你今天可能正在使用那个字符集,但是世界其他地方现在正在使用 UTF-8 并且您也将很快使用它。记住要像维护代码的人一样编写代码,他是一个知道你住在哪里的杀人狂。

      哦,对于使用\d[0-9] 的Perl 模块,即使核心仍然有UNICODE problems

      如果您实际上是指任何数字,但希望能够对结果进行数学运算,您可以使用Text::Unidecode

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      use Text::Unidecode;
      
      my $number = "\x{1811}\x{1812}\x{1813}\x{1814}\x{1815}";
      print "$number is ", unidecode($number), "\n";
      

      经过更多测试,看起来 Text::Unidecode 无法正确处理所有数字字符。我正在写一个module,它会起作用。

      【讨论】:

        【解决方案5】:

        如果您将\d 应用于Unicode 字符串(例如"\X{660}" =~ /\d/),它将匹配Unicode 数字。如果将\d 应用于二进制字符串(例如上面的UTF-8 等效项:"\xd9\xa0" =~ /\d/),它将仅匹配10 个ASCII 数字。 Perl 5.8 默认不创建 Unicode 字符串(除非您特别要求,例如在 "\X{...}"use utf8; 等中)。

        所以我的建议是:如果您的应用程序使用 Unicode 字符串,请仅注意 \d[0-9] 之间的区别。

        【讨论】:

          【解决方案6】:

          我觉得两者都必须有自己的位置。但是,99.999% 的时间(尤其是在我封闭的美国大合作世界中)它们是可以互换的。我每天都使用 perl 来处理数据,在我处理的所有数据集中都没有不适合 [0-9] 的数字。但是,我确实很欣赏\d[0-9] 之间的重要区别,很高兴了解这种区别。我使用 \d 是因为它看起来更简洁(如您所说),并且在我的数据操作小世界中永远不会“错误”。

          【讨论】:

          • 你想要 \d 而不是 /d - 如果你想要的话。
          【解决方案7】:

          如果[0-9] 感觉笨拙,也许您可​​以定义:$d=qr/[0-9]/; 并使用它来代替\d

          【讨论】:

            【解决方案8】:

            随着数据格式控制的增加,对模式特异性的需求下降......

            例如,如果您要匹配的数据是机器生成的,并且始终遵循相同的输出格式规则,则无需如此精确。 获取 IPv4 地址。如果您尝试从路由器接口配置行中提取 IP 地址,您真正需要的是:

             'ip\haddress\h(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\D'
            

            另一方面,如果您正试图找到一个嵌入在某处深处的 IP 地址,例如,电子邮件 X-Header,或者如果您正试图验证一个 IP 地址,那么……这是一个完整的 '另一个故事!

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多