RegEx字词表现:\ w与[a-zA-Z0-9_]

Emm*_*mma 2 php c# regex perl pcre

我想知道通过的字符列表,\w仅仅是它[a-zA-Z0-9_]还是可以覆盖更多字符?

我问这个问题,是因为基于\d是不同的[0-9],是低效率的

\wvs [a-zA-Z0-9_]:大规模中哪一个更快?

ike*_*ami 5

[ 此答案是Perl特定的。其中的信息可能不适用于PCRE或其他已标记语言使用的引擎。]

/\w/aa(实际等于/[a-zA-Z0-9_]/)通常更快,但并非总是如此。就是说,差异是如此之小(每次检查少于1纳秒),所以不必担心。放到上下文中,调用一个子程序或启动正则表达式引擎需要花费很长时间。

接下来的内容将对此进行详细介绍。


首先,\w[a-zA-Z0-9_]默认设置不同。\w匹配每个字母,数字,标记和连接器标点的Unicode Code Point。其中有119,821![1]确定哪个是最快的非等效代码是没有道理的。

但是,使用\wwith /aa可确保\w仅match [a-zA-Z0-9_]。这就是我们将用于基准测试的内容。(实际上,我们将两者同时使用。)

(请注意,每个测试执行1000万次检查,因此10.0 / s的速率实际上意味着每秒1000万次检查。)


ASCII-only positive match
               Rate [a-zA-Z0-9_]      (?u:\w)     (?aa:\w)
[a-zA-Z0-9_] 39.1/s           --         -26%         -36%
(?u:\w)      52.9/s          35%           --         -13%
(?aa:\w)     60.9/s          56%          15%           --
Run Code Online (Sandbox Code Playgroud)

当找到ASCII字符匹配项时,纯ASCII \w和Unicode \w都击败了显式类。

/\w/aa 在我的机器上快了(1 / 39.1-1 / 60.9)/ 10,000,000 = 0.000,000,000,916 s


ASCII-only negative match
               Rate      (?u:\w)     (?aa:\w) [a-zA-Z0-9_]
(?u:\w)      27.2/s           --          -0%         -12%
(?aa:\w)     27.2/s           0%           --         -12%
[a-zA-Z0-9_] 31.1/s          14%          14%           --
Run Code Online (Sandbox Code Playgroud)

如果无法找到ASCII字符的匹配项,则显式类将击败ASCII-only \w

/[a-zA-Z0-9_]/ 在我的机器上快了(1 / 27.2-1 / 31.1)/ 10,000,000 = 0.000,000,000,461 s


Non-ASCII positive match
               Rate      (?u:\w) [a-zA-Z0-9_]     (?aa:\w)
(?u:\w)      2.97/s           --        -100%        -100%
[a-zA-Z0-9_] 3349/s      112641%           --          -9%
(?aa:\w)     3664/s      123268%           9%           --
Run Code Online (Sandbox Code Playgroud)

哇 该测试似乎正在进行一些优化。也就是说,多次运行测试会产生极其一致的结果。(其他测试也一样。)

当找到非ASCII字符的匹配项时,仅ASCII会\w击败显式类。

/\w/aa 在我的机器上快了(1/3349-1/3664)/ 10,000,000 = 0.000,000,000,002,57 s


Non-ASCII negative match
               Rate      (?u:\w) [a-zA-Z0-9_]     (?aa:\w)
(?u:\w)      2.66/s           --          -9%         -71%
[a-zA-Z0-9_] 2.91/s          10%           --         -68%
(?aa:\w)     9.09/s         242%         212%           --
Run Code Online (Sandbox Code Playgroud)

如果找不到非ASCII字符的匹配项,则仅ASCII会\w击败显式类。

/[a-zA-Z0-9_]/ 在我的机器上快了(1 / 2.91-1 / 9.09)/ 10,000,000 = 0.000,000,002,34 s


结论

  • 我很惊讶/\w/aa和之间有任何区别/[a-zA-Z0-9_]/
  • 在某些情况下,/\w/aa速度更快;在其他人中,/[a-zA-Z0-9_]/
  • /\w/aa和之间的差异/[a-zA-Z0-9_]/非常小(小于1纳秒)。
  • 差别很小,您不必担心。
  • 即使之间的差别/\w/aa,并/\w/u是,尽管后者匹配4个数量级比以前更多的字符相当小。

use strict;
use warnings;
use feature qw( say );

use Benchmarks qw( cmpthese );

my %pos_tests = (
   '(?u:\\w)'     => '/^\\w*\\z/u',
   '(?aa:\\w)'    => '/^\\w*\\z/aa',
   '[a-zA-Z0-9_]' => '/^[a-zA-Z0-9_]*\\z/',
);

my %neg_tests = (
   '(?u:\\w)'     => '/\\w/u',
   '(?aa:\\w)'    => '/\\w/aa',
   '[a-zA-Z0-9_]' => '/[a-zA-Z0-9_]/',
);

$_ = sprintf( 'use strict; use warnings; our $s; for (1..1000) { $s =~ %s }', $_)
   for
      values(%pos_tests),
      values(%neg_tests);

local our $s;

say "ASCII-only positive match";
$s = "J" x 10_000;
cmpthese(-3, \%pos_tests);

say "";

say "ASCII-only negative match";
$s = "!" x 10_000;
cmpthese(-3, \%neg_tests);

say "";

say "Non-ASCII positive match";
$s = "\N{U+0100}" x 10_000;
cmpthese(-3, \%pos_tests);

say "";

say "Non-ASCII negative match";
$s = "\N{U+2660}" x 10_000;
cmpthese(-3, \%neg_tests);
Run Code Online (Sandbox Code Playgroud)
  1. Unicode版本11。