在过去几周阅读了一些问题/答案后,我看到在perl正则表达式中使用\d
被评论为不正确。与更高版本的perl \d
与[0-9]
不同,因为\d
将表示具有digit属性的任何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
答案 0 :(得分:53)
在我看来使用\d
非常危险,这在语言中是一个糟糕的设计决策,因为在大多数情况下你需要[0-9]
。霍夫曼编码将规定\d
用于ASCII数字。
以前的大多数海报都已经强调了为什么要使用[0-9]
,所以让我再给你一些数据:
如果我正确阅读了unicode图表,那么'۷۰
'是一个数字(70 in in indic,请不要相信我的话)。
试试这个:
$ 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 :(得分:38)
为了最大限度地提高安全性,我建议您在没有特别打算匹配所有unicode定义的数字时使用[0-9]
。
Per perldoc perluniintro,Perl不支持使用[0-9]
以外的数字作为数字,所以如果以下两者都为真,我肯定会使用[0-9]
:
您希望将结果用作数字(例如对其执行数学运算或将其存储在仅接受正确数字的位置(例如,数据库中的INT列))。
数据中可能存在非数字[^0-9]
,正则表达式可以匹配它们。 (请注意,对于不受信任/恶意的输入,此始终应被视为true。)
如果其中任何一个都是假的,那么很少有理由不使用\d
(并且您可能能够判断何时是这种情况),并且如果您尝试匹配所有unicode定义的数字,那么您肯定希望使用\d
。
答案 2 :(得分:8)
根据perlreref,“\d
”具有区域设置感知和Unicode识别功能。
但是,如果您使用的代码集不是Unicode,那么您不必担心Unicode数字,如果您使用的代码集类似于Latin-1(ISO 8859-1或8859-) 15),那么语言环境感知不会对你造成伤害,因为代码集不包含任何其他数字字符。
因此,对于许多人来说,大多数情况下,您可以毫无顾虑地使用“\d
”。但是,如果Unicode数据是您工作的一部分,那么您需要更仔细地考虑您的内容。
答案 3 :(得分:5)
就像从轨道上钻取网站一样,[0-9]
是确保唯一的方法。是的,它很难看。是的,让\d
成为UNICODE和语言环境的选择是愚蠢的。但这是我们的床,我们必须躺在床上。
至于人们在沙滩上低头说它不会影响他们今天使用的角色,你今天可能正在使用这个角色,但世界其他地方现在正在使用UTF-8你很快就会使用它。记住代码就像那个维护你的代码的人是一个杀人的疯子,他知道你住在哪里。
哦,对于使用\d
vs [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。
答案 4 :(得分:3)
我觉得他们必须有自己的位置。但是,99.999%的时间(特别是在我封闭的美国大合作世界中)它们是可以互换的。我每天都使用perl来操作数据,而我处理的数据集中没有一个数字不适合[0-9]
。但是,我确实感谢\d
和[0-9]
之间存在重要区别,并且了解这种差异是很好的。我使用\d
因为它看起来更简洁(正如你所说)并且在我的小数据操作世界中永远不会“错误”。
答案 5 :(得分:2)
如果将\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 :(得分:1)
如果[0-9]
感觉笨拙,也许你可以定义:$d=qr/[0-9]/;
并使用它代替\d
。
答案 7 :(得分:0)
随着数据格式控制的增加,对模式特异性的需求下降......
例如,如果要匹配机器生成的数据并且始终遵循相同的输出格式规则,则不需要如此精确。 获取IPv4地址。如果您尝试从路由器接口配置行中提取IP地址,您真正需要的就是:
'ip\haddress\h(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\D'
另一方面,如果您正在尝试查找嵌入在电子邮件X-Header中某处的IP地址,或者如果您尝试验证IP地址,那么这就是整个& #39;其他故事!