【问题标题】:Grep & Perl regex negative lookbehind not workingGrep & Perl 正则表达式负向后看不起作用
【发布时间】:2016-06-07 10:08:04
【问题描述】:

我想在 grep+perl 中使用正则表达式,以便在 finally 子句中选择 unclosed java 语句。

我想出的模式应该选择所有 .submitBacth();前面没有finally {

但是,由于返回了所有匹配项,因此后面的负面外观似乎并不正确或按预期工作。

myself@mymachine:~/Desktop$ grep -C 3 -P '(?s)(?<!finally\s\{.).*?\.submitBatch\(\)\;' ~/myfile.txt

示例文本(myfile.txt):

        //sample text
        batch.addToBatchUpdate(item1);
    }
    batch.submitBatch();
    dao.update(item2);
    //another text
} finally {

--

        }
    }
} finally {
    impl.submitBatch();
    test.close();
}

预期的输出应该是:

                //sample text
                batch.addToBatchUpdate(item1);
            }
            batch.submitBatch();
            dao.update(item2);
            //anotehr text
        } finally {

我本来希望只看到第一个条目 batch.submitBatch();但如您所见,两者都返回了。

【问题讨论】:

  • 请使用适当的输入字符串和所需的输出字符串来说明您的问题。
  • 正则表达式可能是解析上下文语言的错误选择。他们根本做不到。
  • this post中的回答几乎相同

标签: regex perl grep


【解决方案1】:

在 Perl 中你可以使用

$regex_new = /( (?:finally\s+\{\s+|.) )(\S+\.submitBatch\(\)\; ) /sx;

从文件中提取带有.submitBatch 的子字符串。如果第一个捕获组($1 的内容)以 finally 开头,则可以忽略该匹配项(因为您想排除这些匹配项)。

关于你原来的正则表达式,

$regex = /( (?<!finally\s\{.) .*? \.submitBatch\(\)\; )/sx;

这里有什么问题?它会比需要的匹配更多,并且很难提取您正在寻找的匹配。

例如:

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

use Term::ANSIColor;

my $str = do { local $/; <DATA> };
my $regex = /( (?<!finally\s\{.) .*? \.submitBatch\(\)\; )/sx;
$str =~ s/$regex/color_match( $1 )/ge;
say $str;

sub color_match {
    state $i = 0;
    state $colors = [qw[red green blue]];
    return color( "bold " . $colors->[$i++] ) . $_[0] . color("reset");
}

__DATA__
         ... code ...
       } finally {
         impl.submitBatch();
         test.close();
     }
     batch.addToBatchUpdate(item1);
  }
  batch.submitBatch();
  dao.update(item2);
  //another text
} finally {
  impl.submitBatch();
  test.close();
}

输出是:

所以每个匹配都以.submitBatch(); 结尾,但否定的后向断言(?&lt;!finally\s\{.) 立即匹配g 修饰符的每次迭代。例如,对于第一次迭代,它匹配文件的开头,然后 .*? 匹配所有直到第一个 .submitBatch(); 并完成第一次迭代(无需回溯)。其他比赛也是如此。

如果我们将$regex 替换为$regex_new,输出将是:

现在很容易排除错误匹配。 例如,您可以使用e 修饰符:

$str =~ s/$regex/fix_missing_finally_clause( $1, $2)/ge;

在哪里(例如):

sub fix_missing_finally_clause {
    if ($_[0] =~ /^finally/ ) {
        return $_[0].$_[1];
    }  
    else {
        # Insert your edits here... for example:
        return "finally {\n" . $_[0] . $_[1] . "\n\t}\n";
    }
}

【讨论】:

    【解决方案2】:

    感谢 Håkon 的详细回答,但我更喜欢使用 grep 的 perl 扩展,因为我有其他正则表达式,我不想用 perl 重写所有脚本(我喜欢让我的脚本保持整洁可能),即使可能更容易。 我终于设法用这个修复了正则表达式,它还注意在方法签名和我感兴趣的方法之间进行查看。

    我知道正则表达式选择太多,但我不是专家,我对替换不感兴趣,所以只要有适合我的匹配就足够了。

    myself@mymachine:~$grep -Pzo '(?s)(?<=public|private|protected).(?<!finally).*?\.submitBatch\(\)\;' /tmp/test.java
         method
        //sample text
                batch.addToBatchUpdate(item1);
            }
            batch.submitBatch();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-26
      相关资源
      最近更新 更多