在开始正则表达式和结束正则表达式之间的字符串中替换

时间:2019-02-28 22:44:18

标签: regex perl

我只想在字符串中进行多个替换,但仅在开始正则表达式和结束正则表达式之间进行。例如:

$start = qr/a.*?b/;
$end = qr/c.*?d/;
$string = 'a1b x c2d x a345b qqxxxc678d xx abxcd';

perl代码将执行受限的s/x/y/g。它将xa.*?b之间出现的所有c.*?d更改为y,以便随后:

$string = 'a1b y c2d x a345b qqyyyc678d xx abycd'

2 个答案:

答案 0 :(得分:4)

仅需要在标记模式中进行全局替换的复杂问题可以通过捕获子字符串并在替换部分中运行正则表达式来处理

my $s = q(a1b x and x c2d x more x  a22b x again x c33d x and x); 

$s =~ s/a.*?b\K(.*?)(?=c.*?d)/$1=~s{x}{y}gr/eg;

say $s;

我在左侧标记模式(\K)之后使用a.*?b删除先前的匹配项,并为右侧标记模式(c.*?d)进行前瞻,因此不要复制这些标记周围,​​但为简单起见,您可以捕获它们,并在替换中使用数字变量($N)。

如果图案重复,请考虑捕获正确的标记(而不是超前标记);那么对于额外的数据副本,不会重复扫描该子模式,并且整个正则表达式更整洁,并且原则上更安全(右标记可能包含左标记吗?)。这确实使替换部分变得复杂,在新的正则表达式中,$2需要保存在/r中,因为它已在其中重置。

请注意替换零件的正则表达式中的s///修饰符:除了非常方便之外,它还允许我们在$1变量上使用my $start = qr/a.*?b/; my $end = qr/c.*?d/; my $s = q(a1b x and x c2d x more x a22b x again x c33d x and x); $s =~ s/$start\K (.*?) (?=$end)/ $1 =~ s{x}{y}gr /egx; say $s; ,否则我们将无法做它是只读的。

如果这是更复杂的正则表达式处理的一部分,请注意,超前是零宽度的 asserttion ,因此引擎不会使用该模式并且不会通过该模式。如果整个模式重复出现,这很重要:如果右标记可能包含左标记,那么您必须捕获它,以便引擎在下一场比赛中越过它,以便左标记先出现。


这适用于标记样式的变量,您可以很好地使用

/x

根据Array.forEach,我在其中间隔了一些模式以提高可读性。它打印

a1b y and y c2d x more x  a22b y again y c33d x and x

答案 1 :(得分:1)

您可以使用修改后的/e来执行代码(分别针对每个匹配项)以生成替换字符串:

use strict;
use warnings;

my $start_regex  = qr/a.*?b/;
my $end_regex    = qr/c.*?d/;
my $string = 'a1b x c2d x a345b qqxxxc678d xx abxcd';

$string =~ s/($start_regex)(.*?)($end_regex)/ my ($start_match, $middle_match, $end_match) = ($1, $2, $3); $middle_match =~ s!x!y!g; $start_match . $middle_match . $end_match /eg;

print $string, "\n";

将打印出

a1b y c2d x a345b qqyyyc678d xx abycd

请注意内部正则表达式中的替代正则表达式定界符s!!!

将外部正则表达式的$1$2$3存储在临时变量中非常重要,因为当您在替换代码中执行另一个正则表达式时,它们会丢失。