我应该使用d或[0-9]来匹配Perl正则表达式中的数字吗?

Should I use d or [0-9] to match digits in a Perl regex?

在过去几周阅读了大量的问题/答案后,我发现在perl正则表达式中使用\d被认为是不正确的。与Perl \d的较新版本不同,\d表示具有数字属性的任何Unicode字符,而[0-9]表示字符'0'、'1'、'2'、…、'9'。

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

就我个人而言,我发现\d符号非常简洁和富有表现力,而相比之下,[0-9]有些麻烦。但是我很少有做多语言代码的经验,或者更确切地说,对于那些不适合于ASCII字符范围的语言,代码可能是幼稚的。

我注意到了

1
2
3
4
$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

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

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

  • 如果我正确地阅读了Unicode图表,"??"是一个数字(70的印度语,不要相信我的话)。

  • 试试这个:

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     ZERO:  0??????????????
     ONE:   1??????????????
     TWO:   2??????????????
     THREE: 3??????????????
     FOUR:  4??????????????
     FIVE:  5??????????????
     SIX:   6??????????????
     SEVEN: 7??????????????
     EIGHT: 8??????????????
     NINE:  9????????????????

你还不相信吗?


为最大安全,我会建议使用[0-9]任何时间你不特别想所有Unicode -定义到比赛地点。

每perldoc perluniintro地点,不支持使用Perl做为其他煤炭[0-9]绝对数量,所以我会使用以下两[0-9]如果是真实的:

  • 你想使用的结果作为一个编号(如进行数学在它或它的作战storing某处,只有接受适当数量(例如安全列在一个数据库int))。

  • 它是可能的非[^0-9]地点会在目前的数据在这一表达方式,regular能匹配他们。(注意,这个应该是被视为一个"真正的"总是untrusted / hostile输入。)

  • 如果这是要么是false,将只有很少有特别的理由不使用\d(和可能是你会告诉这是能当的情况),如果你想匹配所有Unicode -定义的地点,你会想使用\d绝对。


    根据perlreref,\d"是locale -清楚自己清楚自己和Unicode。

    然而,如果你是使用的codeset不是Unicode,然后你不需要担心关于Unicode的地点,如果你是使用的是什么codeset像拉丁语1(ISO 8859 - 1,或8859 15),然后一个宣传的locale不会伤害你-无论是因为codeset不包括对其他任何位数的特点。

    所以,对于许多人,多的时间,你可以使用"\d"没有关注的问题。然而,如果Unicode数据的工作的一部分,然后你需要什么后,则认为是更仔细。


    就像nuking网站从[0-9]轨道,是唯一的方法是确定的。是的,它是丑陋的。是的,大的选择是让\dUnicode和locale清楚自己是愚蠢的。但这是我们有大的床和躺在它。

    作为为他们的头的人在美国ducking说这并不影响他们是今天使用的字符集,以及使用字符集,你可能今天,但其余的世界是现在使用UTF-8,你将很快使用它为好。记得大像的家伙谁maintains代码的代码是一个homicidal maniac谁知道在你的生活。

    哦,和作为modules \dVS [0-9]为Perl使用Unicode的核心,即使仍然有问题。

    如果你做任何位数的平均情况,但要成为能与自由的数学结果,你可以使用Text::Unidecode

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/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),"
    "
    ;

    它看起来像一些更多的测试后不unidecode文本:所有位数的基础上正确处理的特点。我是写作的一个模块,将工作。


    我感觉都必须有他们的地方。然而,99.999%的时间(尤其是在美国的世界封闭的大合作,他们是interchangeable)。我每天使用Perl中用来操纵数据的大数据集,在所有与我交易的数量,是有别fit在[0-9]。然而,我是一个重要的原因,有appreciate \dand[0-9]之间的区别,它是大的,很清楚自己的区别。我使用\d似乎更succinct(因为它会为你说)和"错误的"永远是在我的小世界的数据操作。


    如果你到一个Unicode应用\d弦乐(如在比赛"\X{660}" =~ /\d/),它将一个Unicode位数。如果你\d应用到一个二进制的弦乐(如UTF-8等效研究:"\xd9\xa0" =~ /\d/以上),它将ASCII码只有10的比赛地点。5.8 Perl不创建Unicode字符串由安装默认的(除非你为它特别要求,如在"\X{...}"use utf8;等)。

    所以我的建议是:只有付出注意力的差异之间的\d[0-9]如果你的应用使用Unicode字符串。


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


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

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

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

    另一方面,如果你试图在某个地方找到一个IP地址,比如电子邮件的X头,或者如果你试图验证一个IP地址,那么……这是一个完整的"另一个故事"!