Perl正则表达式如何重复使用上一场比赛的一部分进行下一场比赛?

时间:2009-08-16 01:52:38

标签: regex perl

我需要一些Perl正则表达式帮助。以下代码片段:

use strict; 
use warnings; 
my $str = "In this example, A plus B equals C, D plus E plus F equals G and H plus I plus J plus K equals L"; 
my $word = "plus"; 
my @results = ();
1 while $str =~ s/(.{2}\b$word\b.{2})/push(@results,"$1\n")/e;
print @results;

产生以下输出:

A plus B
D plus E
2 plus F
H plus I
4 plus J
5 plus K

我想看到的是,已经匹配的角色可以出现在不同背景下的新匹​​配中:

A plus B
D plus E
E plus F
H plus I
I plus J
J plus K

如何更改正则表达式以获得此结果?谢谢---丹

6 个答案:

答案 0 :(得分:6)

一般建议:如果需要s///,请勿使用m//。具体在你匹配的内容。

答案是pos

#!/usr/bin/perl -l

use strict;
use warnings;

my $str = 'In this example, ' . 'A plus B equals C, ' .
          'D plus E plus F equals G ' .
          'and H plus I plus J plus K equals L';

my $word = "plus";

my @results;

while ( $str =~ /([A-Z] $word [A-Z])/g ) {
    push @results, $1;
    pos($str) -= 1;
}

print "'$_'" for @results;

输出:

C:\Temp> b
'A plus B'
'D plus E'
'E plus F'
'H plus I'
'I plus J'
'J plus K'

答案 1 :(得分:3)

您可以使用m//g代替s///并指定pos功能,以便在第二个词之前回放匹配位置:

use strict;
use warnings;

my $str  = 'In this example, A plus B equals C, D plus E plus F equals G and H plus I plus J plus K equals L';
my $word = 'plus';
my @results;

while ($str =~ /(.{2}\b$word\b(.{2}))/g) {
    push @results, "$1\n";
    pos $str -= length $2;
}
print @results;

答案 2 :(得分:2)

另一个选择是使用前瞻:

use strict; 
use warnings; 
my $str = "In this example, A plus B equals C, D plus E "
        . "plus F equals G and H plus I plus J plus K equals L"; 
my $word = "plus"; 
my $chars = 2;
my @results = ();

push @results, $1 
  while $str =~ /(?=((.{0,$chars}?\b$word\b).{0,$chars}))\2/g;

print "'$_'\n" for @results;

在前瞻中,捕获组1匹配单词以及可变数量的前导和尾随上下文字符,直到您设置的最大值。当前瞻结束时,后向引用\2匹配“实际”任何由第2组捕获的内容,这与第1组相同,除了它在单词的结尾处停止。这会将pos设置在您想要的位置,而无需计算您在单词后实际匹配的字符数。

答案 3 :(得分:1)

鉴于“完全披露”评论(但假设是.{0,35},而不是.{35}),我会做

use List::Util qw/max min/;
my $context = 35;
while ( $str =~ /\b$word\b/g ) {
    my $pre = substr( $str, max(0, $-[0] - $context), min( $-[0], $context ) );
    my $post = substr( $str, $+[0], $context );
    my $match = substr( $str, $-[0], $+[0] - $-[0] );
    $pre =~ s/.*\n//s;
    $post =~ s/\n.*//s;
    push @results, "$pre$match$post";
}
print for @results;

如果你的意思是(?s:.{0,35}),你会跳过替换。

答案 4 :(得分:0)

这是一种方法:

use strict; 
use warnings; 
my $str = "In this example, A plus B equals C, D plus E plus F equals G and H plus I plus J plus K equals L"; 
my $word = "plus"; 
my @results = ();
my $i = 0;
while (substr($str, $i) =~ /(.{2}\b$word\b.{2})/) {
    push @results, "$1\n";
    $i += $-[0] + 1;
}
print @results;

这不是非常糟糕的Perl-ish,但是它有效并且它不会使用太多模糊的正则表达技巧。但是,您可能必须在perlvar中查找特殊变量@-的功能。

答案 5 :(得分:0)

不必使用正则表达式。基本上,只需分割字符串,使用循环遍历每个项目,检查“加号”,然后从前后获取单词。

my $str = "In this example, A plus B equals C, D plus E plus F equals G and H plus I plus J plus K equals L"; 
@s = split /\s+/,$str;
for($i=0;$i<=scalar @s;$i++){
    if ( "$s[$i]"  eq "plus" ){
        print "$s[$i-1] plus $s[$i+1]\n";
    }
}