【问题标题】:Perl regex replace countPerl 正则表达式替换计数
【发布时间】:2011-06-26 16:58:26
【问题描述】:

是否可以指定要替换的最大匹配数。例如,如果匹配“Hello World”中的 'l',是否可以替换前 2 个 'l' 字符,但不能替换第三个而不循环?

【问题讨论】:

  • 你可以使用 python re.sub(repl, string[, count=0]),但这显然不是你想要的。
  • 这可能是升级到 Python 所需的动力。
  • @Quick:起来了吗?当然,你的意思是向下。
  • 我喜欢写 Perl,但我不是特别喜欢回读。

标签: regex perl


【解决方案1】:
$str = "Hello world!";
$str =~ s/l/r/ for (1,2);
print $str;

我看不出循环有什么不好。

其实有一个办法:

$str="Hello world!"; 
$str =~ s/l/$i++ >= 2 ? "l": "r"/eg; 
print $str;

这是一个循环,因为 s///g 在您执行此操作时会以循环方式工作。但不是传统的循环。

【讨论】:

  • 后一种方式如何“循环”?它只遍历字符串一次,对吧?
  • @Tim Nordenfur:每次找到匹配项时都会进行评估,但是是的,只遍历字符串一次。你可以做while (/match/g) 来创建一个循环。
  • 每个方法都是一个循环。有显式循环(看起来像“while”或“foreach”的循环,以及隐式循环(没有名称但发生在幕后的循环)。没有隐式循环就没有遍历(甚至一次)。它只是隐藏在 RE 引擎的 /g 子句中。
【解决方案2】:

这是一种方法。这需要使用(?(condition)true-sub-expression|false-sub-expression) 构造内的(?{code}) 块在RE 内更新外部计数器。请参阅perldoc perlre 了解说明。

use Modern::Perl;
use re qw/eval/; # Considered experimental.

my $string = 'Hello world!';

my $count = 2;

my $re =    qr/
                (l)
                (?(?{$count--})|(*FAIL))
            /x;

say "Looking for $count instances of 'l' in $string.";
my ( @found ) = $string =~ m/$re/g;
say "Found ", scalar @found, " instances of 'l': @found";

输出是:

Looking for 2 instances of 'l' in Hello world!
Found 2 instances of 'l': l l

这是对相同正则表达式的另一个测试,但这次我们跟踪匹配项的位置只是为了证明它与前两次匹配。

use Modern::Perl;
use strict;
use warnings;
use re qw/eval/; # Considered experimental.

my $string = 'Hello world!';

my $count = 2;
my $position = 0;

my $re =    qr/
                (l)(?{$position=pos})
                (?(?{$count--})|(*FAIL))
            /x;

while( $string =~ m/$re/g ) {
    say "Found $1 at ", $position;
}

而这次的输出是:

Found l at 3
Found l at 4

我不认为我会推荐这些。如果我正在考虑将匹配限制在字符串的一部分,我会匹配字符串的substr()。但是,如果您喜欢生活在边缘,请继续享受这个 sn-p 的乐趣。

这里是替换:

use Modern::Perl;
use strict;
use warnings;
use re qw/eval/; # Considered experimental.

my $string = 'Hello world!';
say "Before substitution $string";
my $count = 2;
my $re =    qr/
                (l)
                (?(?{$count--})|(*FAIL))
            /x;

 $string =~ s/$re/L/g;

 say "After substitution  $string";

还有输出:

Before substitution Hello world!
After substitution  HeLLo world!

【讨论】:

  • 请注意:我真的很想通过 YAPE::Regex::Explain 运行它以显示正在发生的事情,但不幸的是它没有准确描述正在发生的事情。
  • 另一条评论,如果有人还在阅读:任何涉及嵌入在正则表达式本身中的计数器的方法都可能对 RE 引擎的回溯敏感。只是一个想法。
【解决方案3】:

简短的回答:不。您将需要在某种循环中执行替换。

【讨论】:

  • @re = qw(l l); s/(l)/shift @re || $1/eg;
  • 这很可爱,但它的实用性在某种程度上仅限于最琐碎的正则表达式模式。您在答案中发布的版本更有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-01
  • 2017-08-28
  • 2013-09-27
  • 2018-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多