【问题标题】:How do I substitute overlapping matches with a Perl regex?如何用 Perl 正则表达式替换重叠匹配?
【发布时间】:2011-07-04 13:30:26
【问题描述】:

我想在一个字符串中找到所有出现的"BBB" 并将它们替换为"D"。比如我有"ABBBBC",想生产"ADBC""ABDC"。 (首先替换第一个BBB,然后替换另一个BBB)。在 Perl 中有没有很好的方法来做到这一点?

$str = "ABBBBC";
for ( $str =~ m/B(?=BB)/g ) {
    # I match both the BBBs here, but how to substitute the relevant part?
}

我想得到这个数组:('ADBC', 'ABDC'),它来自将BBBs 中的任何一个更改为D。字符串"ABBBBBC" 将给我"ADBBC""ABDBC""ABBDC"

【问题讨论】:

  • 如果你替换第一个BBB你得到ADBC,那么“其他”BBB在哪里?不明白...
  • @Fredrik- 第一个是 A_BBB_BC,另一个是 AB_BBB_C。我想创建一个包含所有(在这种情况下都是)可能结果的数组
  • 谢谢,现在好多了!
  • 您想要 ABBBBCBBBBE 的输出是什么?

标签: regex perl substitution


【解决方案1】:

要获得重叠匹配,您必须使用 Perl 的 pos 运算符。

pos SCALAR
pos
返回最后一次 m//g 搜索停止的位置的偏移量,以查找相关变量(未指定变量时使用 $_)。请注意,0 是有效的匹配偏移量。 undef 表示搜索位置被重置(通常是由于匹配失败,但也可能是因为尚未在标量上运行匹配)。

pos 直接访问正则表达式引擎用来存储偏移量的位置,因此分配给 pos 会改变该偏移量,因此也会影响正则表达式中的\G 零宽度断言。这两种效果都发生在下一场比赛中,所以你不能在当前比赛中影响pos的位置,例如(?{pos() = 5})s//pos() = 5/e

设置pos 还会重置匹配的长度为零的标志,如Repeated Patterns Matching a Zero-length Substring in perlre 所述。

因为失败的 m//gc 匹配不会重置偏移量,所以在这种情况下,pos 的返回值也不会改变。请参阅perlreperlop

例如:

#! /usr/bin/env perl

use strict;
use warnings;

my $str = "ABBBBC";
my @replaced;
while ($str =~ m/^(.*)\G(.+?)BBB(.*)$/g ) {
  push @replaced, $1 . $2 . "D" . $3;
  pos($str) = length($1) + 1;
}

print "[", join("][" => @replaced), "]\n";

输出:

$ ./prog
[ADBC][ABDC]

【讨论】:

    【解决方案2】:
    local our @replaced;
    'ABBBBC' =~ /^(.*)BBB(.*)\z(?{ push @replaced, $1.'D'.$2 })(?!)/s;
    

    【讨论】:

      猜你喜欢
      • 2018-12-13
      • 1970-01-01
      • 2017-11-10
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 1970-01-01
      • 2012-05-16
      相关资源
      最近更新 更多