【问题标题】:More Efficient Way to Find/Replace Non-Escaped Characters查找/替换非转义字符的更有效方法
【发布时间】:2012-09-20 09:54:50
【问题描述】:

我正在尝试找到最好的方法来查找和替换(在 Ruby 1.9.2 中)前面有 零或偶数个反斜杠的特殊代码 (%x) 的所有实例.

换句话说,:

%x      -->   FOO
\%x     -->   \%x
\\%x    -->   \\FOO
\\\%x   -->   \\\%x
\\\\%x  -->   \\\\FOO
etc.

一个字符串中可能有多个实例:“这是我的 %x 字符串,带有两个 %x 代码。”

herehere 提出的问题的帮助下,我得到了以下代码来做我想做的事:

 str.gsub(/
  (?<!\\)           # Not preceded by a single backslash
  ((?:\\\\)*)       # Eat up any sets of double backslashes - match group 1  
  (%x)              # Match the code itself - match group 2
  /x, 

  # Keep the double backslashes (match group 1) then put in the sub
  "\\1foo")  

不过,那个正则表达式似乎有点重量级。由于此代码将在我的应用程序中以合理的频率调用,因此我想确保我不会错过更好(更清洁/更高效)的方法。

【问题讨论】:

    标签: ruby regex


    【解决方案1】:

    我可以想象两个替代的正则表达式:

    1. 使用后视断言,就像在您的代码中一样。 (向后看2)
    2. 在反斜杠之前再匹配一个字符。 (替代)

    除此之外,我只看到您的正则表达式的小幅优化。 "%x" 是常数,因此您不必捕获它。 (后视-1)

    我不确定其中哪个实际上更有效。因此,我创建了一个小基准:

    $ perl
    use strict;
    use warnings;
    use Benchmark qw(cmpthese);
    
    my $test = '%x \%x \\%x \\\%x \\\\%x \\\\\%x \\\\%x \\\%x \\%x \%x %x';
    
    cmpthese 1_000_000, {
        'look-behind-1' => sub { (my $t = $test) =~ s/(?<!\\)((?:\\\\)*)\%x/${1}foo/g },
        'look-behind-2' => sub { (my $t = $test) =~ s/(?<!\\)((?:\\\\)*)(\%x)/${1}foo/g },
        'alternative'   => sub { (my $t = $test) =~ s/((?:^|[^\\])(?:\\\\)*)\%x/${1}foo/g },
    };
    

    结果:

                      Rate   alternative look-behind-2 look-behind-1
    alternative   145349/s            --          -23%          -26%
    look-behind-2 188324/s           30%            --           -5%
    look-behind-1 197239/s           36%            5%            --
    

    您可以清楚地看到,替代正则表达式远远落后于后视方法,捕获“%x”比不捕获它稍慢。

    问候,马蒂亚斯

    【讨论】:

      猜你喜欢
      • 2021-12-31
      • 1970-01-01
      • 2011-03-02
      • 2021-04-18
      • 1970-01-01
      • 2012-02-14
      • 1970-01-01
      • 1970-01-01
      • 2021-04-25
      相关资源
      最近更新 更多