比方说,一个文本文件有很多$start-$end
对,并且每对内都有一些文本。我希望Perl使用$pattern
对查找并替换所有$start-$end
s;如果$pattern
位于该对之外,则不要替换它。例如:文字:
xx START xx bingo xx bingo xx END xx bingo xx START xx bingo xx END bingo
文本中可能有任何换行符(此处未显示); $pattern
可能会在一对中出现多次。预期结果是:
xx START xx okyes xx okyes xx END xx bingo xx START xx okyes xx END bingo
这项工作似乎很简单,但我只是没有弄清楚Perl正则表达式。有人能帮忙吗?
答案 0 :(得分:3)
查看您的来源'我建议这里的技巧是设置$/
- 记录分隔符。
如果将其设置为单个空格,则可以逐字迭代。 然后使用range operator确定您是否在分隔符内。
示例:
#!/usr/bin/env perl
use strict;
use warnings;
local $/ = ' ';
while ( <DATA> ) {
if ( m/START/ .. /END/ ) {
s/bingo/okyes/g;
}
print;
}
__DATA__
xx START xx bingo xx bingo xx END xx bingo xx START xx bingo xx END bingo
打印:
xx START xx okyes xx okyes xx END xx bingo xx START xx okyes xx END bingo
你可以用一个正则表达式完成这个。我建议您不要,因为它以后会非常复杂和难以理解。
答案 1 :(得分:2)
我发现使用@-
和@+
内置数组与substr
一起作为左值最简单地完成了这样的事情
$-[1]
包含第一次捕获开始的字符串中的偏移量,而$+[1]
包含结束时的偏移量。因此$+[1]-$-[1]
是捕获的部分的长度
此程序会查找所有/START(.+?)END/
,并通过对该子字符串应用正则表达式替换来编辑捕获的部分 - START
和END
之间的区域
根据您使用的实际数据
,您可能需要稍微根据这一点进行操作use strict;
use warnings 'all';
use feature 'say';
my $str = 'xx START xx bingo xx bingo xx END xx bingo xx START xx bingo xx END bingo';
my ($start, $end, $pattern, $replacement) = qw/ START END bingo okyes /;
while ( $str =~ /\b$start\b(.+?)\b$end\b/gs ) {
substr($str, $-[1], $+[1]-$-[1]) =~ s/$pattern/$replacement/g;
}
say $str;
xx START xx okyes xx okyes xx END xx bingo xx START xx okyes xx END bingo
答案 2 :(得分:1)
将START上的每一行拆分为END,并保留一个标志,告诉您是否在范围内。
#!/usr/bin/perl
use warnings;
use strict;
my $inside;
while (<>) {
my @strings = split /(START|END)/;
for my $string (@strings) {
if ('START' eq $string) {
$inside = 1;
} elsif ('END' eq $string) {
undef $inside;
} elsif ($inside) {
$string =~ s/bingo/okyes/g;
}
print $string;
}
}
或者使用散列作为开关更短一些:
#!/usr/bin/perl
use warnings;
use strict;
use Syntax::Construct qw{ // };
my $inside;
while (<>) {
my @strings = split /(START|END)/;
for my $string (@strings) {
$inside = { START => 1,
END => 0,
}->{$string} // $inside;
$string =~ s/bingo/okyes/g if $inside;
print $string;
}
}
答案 3 :(得分:0)
最终使用以下代码来实现我的目标:
$_ = "xx START xx bingo xx bingo xx END xx bingo xx START xx bingo xx END bingo";
print;
print "\n";
$_ =~ s/START.*?END/($s=$&) =~ s,bingo,okyes,g; $s/ge;
print;
这是一个单正则表达式解决方案,使用s///g
正则表达式中的嵌入式表达式和嵌套的s///g
正则表达式。
对于这篇迟到的帖子感到抱歉,但我非常感谢@Sobrique,@ Boorin和@choroba的回复,这些回复很有启发性和帮助。