perl multiline string regex

时间:2014-04-15 14:37:01

标签: regex perl

我尝试通过逐行读取文件来查找文件中的所有字符串(在“或”之间)。

my @strings = ();
open FILE, $file or die "File operation failed: $!";
foreach my $line (<FILE>) {
    push(@strings, $1) if /(['"].*['"])/g;
}
close FILE;

问题是此代码仅适用于单行上的字符串。

print "single line string";   

但我必须匹配多行字符串,如:

print "This is a
multiligne
string";

我该怎么办?

顺便说一下,我知道我的正则表达不够好。因为它应该匹配以“并以完成”开头的字符串(与单引号相同),但如果我们有"not correct string'则不匹配

更新:我的新代码是

my @strings = ();
open FILE, $file or die "File operation failed: $!";
local $/;
foreach my $line (<FILE>) {
    push(@strings, grep { defined and /["']/ } quotewords('\s+', 1, $_));
}
close FILE;

但如果数据是:

print $time . "single line \n";
print "This is a
multiline
string";
print 'single quote string';
print "string with variable ".$time." after variable";

我应该得到:

"single line \n"
"This is a
multiline
string"
'single quote string'
"string with variable "
" after variable"

1 个答案:

答案 0 :(得分:3)

以下是用于解析单引号或双引号的两个正则表达式。请注意,为了能够捕获多行字符串,我已经将所有数据包含在内:

use strict;
use warnings;

my $squo_re = qr{'(?:(?>[^'\\]*)|\\.)*'};
my $dquo_re = qr{"(?:(?>[^"\\]*)|\\.)*"};

my $data = do {local $/; <DATA>};

while ($data =~ /($squo_re|$dquo_re)/g) {
    print "<$1>\n";
}

__DATA__
print $time . "single line \n";
print "This is a
multiline
string";
print 'single quote string';
print "string with variable ".$time." after variable";

但是,因为您尝试解析perl代码,最简单的方法是使用PPI但是:

use strict;
use warnings;

use PPI;

my $src = do {local $/; <DATA>};

# Load a document
my $doc = PPI::Document->new( \$src );

# Find all the barewords within the doc
my $strings = $doc->find( 'PPI::Token::Quote' );
for (@$strings) {
    print '<', $_->content, ">\n";
}

__DATA__
print $time . "single line \n";
print "This is a
multiline
string";
print 'single quote string';
print "string with variable ".$time." after variable";

两种方法输出:

<"single line \n">
<"This is a
multiline
string">
<'single quote string'>
<"string with variable ">
<" after variable">

关于(?&gt; ...)

的更新

以下是双引号正则表达式的注释版本。

my $dquo_re = qr{
    "
        (?:                # Non-capturing group - http://perldoc.perl.org/perlretut.html#Non-capturing-groupings
            (?>            # Independent Subexpression to prevent backtracking (this is for efficiency only) - http://perldoc.perl.org/perlretut.html#Using-independent-subexpressions-to-prevent-backtracking
                [^"\\]*    # All characters NOT a " or \
            )
        |
            \\.            # Backslash followed by any escaped character
        )*                 # Any number of the preceeding or'd group
    "
    }x;

这个正则表达式实际上并不需要independent subexpression (?> ... )。它旨在防止回溯,因为引用的字符串只有一种方式可以匹配,要么我们使用上述规则找到结束引用,要么我们没有。

在处理递归正则表达式时,子表达式更有用,但在这种情况下我总是使用它。我必须稍后进行基准测试,以确定它是否真的只是一个过早的优化。

有关评论的更新

为避免评论,您只需使用我已提出的PPI解决方案即可。它的意思是解析perl代码,并且已经按原样运行。

但是,鉴于这是一个实验室分配,正则表达式解决方案是在循环中设置第二个捕获组以查找注释:

while ($data =~ /($squo_re|$dquo_re)|($comment_re)/g) {
    my $quote = $1,
    my $comment = $2;

    if (defined $quote) {
        print "<$quote>\n";
    } elsif ($defined $comment) {
        print "Comment - $comment\n";
    }
}

以上内容将匹配带引号的字符串或注释。将定义哪个捕获实际匹配,以便您可以知道找到了哪个。您必须提出正则表达式来自行查找评论。