har*_*inn 58 regular-expression wildcards
在正则表达式维基百科的文章,似乎[[:digit:]]
= [0-9]
= \d
。
它们不相等的情况是什么?有什么不同?
经过一些研究,我认为一个区别是括号表达式[:expr:]
依赖于语言环境。
ImH*_*ere 67
是的,它是[[:digit:]]
~ [0-9]
~ \d
(其中 ~ 表示近似)。
在大多数编程语言中(支持的地方)
\d ? `[[:digit:]]` # (is identical to, it is a short hand for).
Run Code Online (Sandbox Code Playgroud)
将\d
在小于情况存在[[:digit:]]
(可用grep -P
,但不是在POSIX)。
123456789 # Hindu-Arabic
阿拉伯数字
?????????? # ARABIC-INDIC
?????????? # EXTENDED ARABIC-INDIC/PERSIAN
?????????? # NKO DIGIT
?????????? # DEVANAGARI
所有这些都可能包含在[[:digit:]]
或 中\d
,甚至有些情况下[0-9]
。
对于具体POSIX BRE或ERE:
在\d
不支持(不属于POSIX但在GNU grep -P
)。
[[:digit:]]
POSIX 要求与数字字符类相对应,而 ISO C 要求它是字符 0 到 9 而不是其他字符。所以只有在 C 语言环境中all [0-9]
, [0123456789]
, \d
and 的[[:digit:]]
意思完全一样。在[0123456789]
没有可能的误解,[[:digit:]]
是更多的实用程序可用,在某些情况下,只意味着[0123456789]
。该\d
由几个实用程序支持。
至于[0-9]
,范围表达式的含义仅由 C 语言环境中的 POSIX 定义;在其他语言环境中,它可能会有所不同(可能是代码点顺序或整理顺序或其他内容)。
所有 ASCII 数字的最基本选项。
始终有效,(AFAICT)没有已知的失败实例。
它只匹配英文数字:0123456789
。
一般认为[0-9]
只是ASCII数字0123456789
。
在某些情况下,这是非常错误的:Linux 在某些语言环境中不是“C”(2020 年 6 月)系统,例如:
认为:
str='0123456789 ?????????? ?????????? ?????????? ??????????'
Run Code Online (Sandbox Code Playgroud)
尝试grep
发现它允许大多数:
$ echo "$str" | grep -o '[0-9]\+'
0123456789
?????????
?????????
?????????
?????????
Run Code Online (Sandbox Code Playgroud)
那个 sed 有一些麻烦。应该只删除0123456789
但删除几乎所有数字。这意味着它接受大多数数字,但不接受一些 9 (???):
$ echo "$str" | sed 's/[0-9]\{1,\}//g'
? ? ? ?
Run Code Online (Sandbox Code Playgroud)
甚至 expr 也遭受同样的 sed 问题:
expr "$str" : '\([0-9 ]*\)' # also matching spaces.
0123456789 ?????????
Run Code Online (Sandbox Code Playgroud)
还有 ed
printf '%s\n' 's/[0-9]/x/g' '1,p' Q | ed -v <(echo "$str")
105
xxxxxxxxxx xxxxxxxxx? xxxxxxxxx? xxxxxxxxx? xxxxxxxxx?
Run Code Online (Sandbox Code Playgroud)
有多种语言:Perl、Java、Python、C。其中[[:digit:]]
(和\d
)要求扩展含义。例如,这个 perl 代码将匹配上面的所有数字:
$ str='0123456789 ?????????? ?????????? ?????????? ??????????'
$ echo "$str" | perl -C -pe 's/[^\d]//g;' ; echo
0123456789????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
这相当于选择具有的Unicode属性所有字符Numeric
和digits
:
$ echo "$str" | perl -C -pe 's/[^\p{Nd}]//g;' ; echo
0123456789????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
哪个 grep 可以重现(特定版本的 pcre 可能具有与 Perl 不同的内部数字代码点列表):
$ echo "$str" | grep -oP '\p{Nd}+'
0123456789
??????????
??????????
??????????
??????????
Run Code Online (Sandbox Code Playgroud)
某些实现可能会将范围理解为不同于纯 ASCII 顺序(例如 ksh93)(在 2018 年 5 月版本(AT&T Research)93u+ 2012-08-01 上测试时):
$ LC_ALL=en_US.utf8 ksh -c 'echo "${1//[0-9]}"' sh "$str"
? ?????????? ?
Run Code Online (Sandbox Code Playgroud)
现在(2020 年 6 月),来自 debian 的相同软件包 ksh93(相同版本 sh (AT&T Research) 93u+ 2012-08-01):
$ LC_ALL=en_US.utf8 ksh -c 'echo "${1//[0-9]}"' sh "$str"
? ? ? ?
Run Code Online (Sandbox Code Playgroud)
在我看来,这是等待发生的错误的确定来源。
thr*_*rig 16
这取决于您如何定义数字;[0-9]
往往只是 ASCII 的(或者可能是其他既不是 ASCII 也不是 ASCII 超集的东西,而是与 ASCII 相同的 10 位数字,只是具有不同的位表示(EBCDIC));\d
另一方面,可以只是纯数字(旧版本的 Perl,或/a
启用了正则表达式标志的现代版本的 Perl ),也可以是 Unicode 匹配,\p{Digit}
其中的数字集比[0-9]
or/\d/a
匹配要大。
$ perl -E 'say "match" if 42 =~ m/\d/'
match
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/\d/'
match
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/\d/a'
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/[0-9]/'
$
Run Code Online (Sandbox Code Playgroud)
perldoc perlrecharclass
有关更多信息,或查阅相关语言的文档以了解其行为方式。
但是等等,还有更多!语言环境也可能会改变\d
匹配的内容,因此\d
匹配的数字可能比完整的 Unicode 集少,并且(希望通常)还包括[0-9]
. 这类似于isdigit(3)
( [0-9]
) 和isnumber(3)
([0-9
加上语言环境中的其他任何内容)之间的 C 差异。
可能有一些调用可以获取数字的值,即使它不是[0-9]
:
$ perl -MUnicode::UCD=num -E 'say num(4)'
4
$ perl -MUnicode::UCD=num -E 'say num("\N{U+09EA}")'
4
$
Run Code Online (Sandbox Code Playgroud)
[0-9]
,[[:digit:]]
和 的不同含义\d
在其他答案中有所介绍。在这里,我想添加正则表达式引擎实现的差异。
[[:digit:]] \d
grep -E ? ×
grep -P ? ?
sed ? ×
sed -E ? ×
Run Code Online (Sandbox Code Playgroud)
所以[[:digit:]]
总是有效,\d
取决于。在 grep 的手册中提到它[[:digit:]]
只是0-9
在C
语言环境中。
PS1:如果你知道更多,请扩大表格。
PS2:测试使用GNU grep 3.1和GNU 4.4。
其他答案中已经很好地解释了理论差异,因此仍有待解释实际差异。
以下是匹配数字的一些更常见的用例:
通常,当您想要处理一些数字时,数字本身位于格式笨拙的文本文件中。您想提取它们以在您的程序中使用。您可能可以知道数字格式(通过查看文件)和您当前的语言环境,因此可以使用任何表单,只要它完成工作即可。\d
需要最少的击键,所以它非常常用。
您有一些不受信任的用户输入(可能来自网络表单),您需要确保它不包含任何意外。也许您想将其存储在数据库中的数字字段中,或者用作 shell 命令的参数以在服务器上运行。在这种情况下,您确实需要[0-9]
,因为它是最严格和可预测的。
您有一些数据不会用于任何“危险”的事情,但很高兴知道它是否是一个数字。例如,您的程序允许用户输入地址,如果输入不包含门牌号,您希望突出显示可能的拼写错误。在这种情况下,您可能希望尽可能广泛,所以[[:digit:]]
要走的路。
这些似乎是数字匹配的三个最常见用例。如果你认为我错过了一个重要的,请发表评论。