如何在正则表达式中使用捕获特定字符串?

时间:2018-08-22 07:43:47

标签: perl

下面是我的正则表达式:

ExecutorService executor = Executors.newSingleThreadExecutor();
tasks.forEach(task -> CompletableFuture.runAsync(task, executor));
executor.shutdown(); // Reclaim all resources

我想捕获包含空格,换行符等的整个函数。我的脚本中有很多函数,但想从整个列表中专门捕获包含“ google”的函数。

Function1(.*?)(google)((.|\n|\r)*?)LAST\);

2 个答案:

答案 0 :(得分:3)

我想我可以用两种模式来做到这一点。第一个提取函数括号之间的内容,第二个检查其中是否包含google

my $pattern = qr/
    Function1\( (.*?) LAST\);
        /sx;

if( $string =~ $pattern and $1 =~ /google\.com/ ) {
    ...
    }
else {
    say "No match!";
    }

regex方法的问题在于,您必须付出更多的努力才能确保模式中结束函数调用的部分也不会出现在数据中。也就是说,如果LAST);可以在那些字段之一中,则可能会失败。到那时,您将可以更好地使用逐步解析字符串的东西。


这是一个更为复杂的答案,它使用了功能强大但经常被忽略的正则表达式解析功能。

  • 标量上下文中的全局匹配/g会记住其在字符串中的结束位置。
  • 您可以使用pos()
  • 查看该职位
  • \G将比赛的下一部分锚定在pos()
  • /c选项告诉匹配运算符,如果匹配失败,则不要重置位置
  • 使用多个正则表达式和/c,您可以尝试不同的方法,直到其中之一起作用为止。

这是一个小例子。有一个外部if可以检查您是否在函数调用中。一旦进入该if块,继续循环(此处为redo,但这只是一种方式),同时可以匹配其他模式。在函数调用结束时匹配模式时,请跳出循环(last)。

肉是在括号内查找事物的模式。该模式以"开头和结尾,然后查找非引号或转义引号的字符。这是我先前程序的改进,因为该模式不会比您预期的更早终止。请注意,我将URL值调整为转义了引号和LAST);,这将导致我先前的解决方案失败(可能是误报)。

还有另一个好处。我知道函数调用中的哪个键具有哪个值,并且所有这些都以哈希结尾。如果除URL以外的其他键包含字符串google,您在先前的解决方案中可能还会得到其他误报:

$_ = <<'HERE';
Function1("query",
    "URL=https://\"LAST);clients1.goggle.com/tbproxy...",
    "TargetFrame=",
    "Resource=1",
    "RecContentType=text/proto",
    "Referer=",
    "Snapshot=t103.inf",
    LAST);
HERE


my %hash;
if( / Function1 \( \s* /xg ) {
    LOOP: {
        if( / \G LAST \s* \) \s* ; /xgc ) {
            say "Matched end";
            last;
            }

        if( / \G " ( (?: [^"] | \\ " )+ ) " , \s* /xgc ) {
            my $found = $1;
            my( $field, $value ) = split /=/, $found, 2;
            $hash{$field} = $value;
            redo;
            }

        warn "Shouldn't be here!\n";
        }
    }

use Data::Dumper;
say Dumper( \%hash );

通过将其全部隐藏在子例程中来改善这一点(无论您使用哪种解决方案都是一个好习惯)。

if( is_google($string) ) { say "Found Google" }
else                     { say "Didn't find Google" }

sub is_google {
    my( $string ) = @_;

    my %hash;
    if( / Function1 \( \s* /xg ) {
        LOOP: {
            if( / \G " ( (?: [^"] | \\ " )+ ) " , \s* /xgc ) {
                my $found = $1;
                my( $field, $value ) = split /=/, $found, 2;
                $hash{$field} = $value;
                redo;
                }

            if( / \G LAST \s* \) \s* ; /xgc ) {
                say "Matched end";
                last;
                }

            warn "Shouldn't be here!\n";
            }
        }

    return $hash{URL} =~ /google\.com/ ? 1 : ();
    }

答案 1 :(得分:0)

确实很丑陋,但是可以满足您的需求: Function1([^\n]*\n+)+(.*?)URL=(.*?)google.com(.*)([^\n]*\n+)+(.*) 希望其他人可以改善这一点,但是您有一个起点