我选择了如下所示的文本。我需要对其进行基本编辑,但无法理解我需要的正则表达式。也许只是漫长的一天,我没有看到我需要的东西。
示例数据:
START ITEM = 1235
BEGIN
WORD
RATE = 98
MORE WORDS
CODE = XX
STUFF
END
BEGIN
TEXT
MORE WORDS
RATE = 57
ADDITIONAL TEXT
CODE = YY
OTHER THINGS
END
STOP
START ITEM = 9983
BEGIN
WORD
RATE = 01
MORE WORDS
CODE = AA
STUFF
END
BEGIN
TEXT
MORE WORDS
RATE = 99
ADDITIONAL TEXT
CODE = XX
OTHER THINGS
END
STOP
我得到了一个 CODE
和一个 ITEM
编号,需要在适当的 BEGIN
/END 中编辑费率
部分。幸运的是,这些部分使用 STOP
/START
BEGIN
/END
进行了明确定义(它们是关键字,并且不在其他任何地方)。
我的工具箱是 Perl 正则表达式。*
我尝试的第一个解决方案没有用(值硬编码):
$tx =~ s/(START \s ITEM \s = \s 9983.*?
BEGIN
.*?
RATE \s = \s )\d+
(.*? # Goes too far
CODE \s = \s XX)
/$1$newRate$2
/sx;
因为指示的代码最终匹配太多,找到更远的正确代码但总是编辑第一个条目。
建议?
*
实际代码依赖于将正则表达式添加到正则表达式堆栈(一种后处理过滤器)中,每个正则表达式依次应用于文本以进行编辑。哎呀,如果我有文本,我可以做一个完整的解析器。但我希望不必打开该代码并坚持使用我已有的 API。
请您参考如下方法:
正则表达式不太适合解决此类问题。我推荐一个简单的迭代解决方案:
while (<FILE>) {
# push lines straight to output until we find the START that we want
print OUT $_;
next unless m/START ITEM = $number/;
# save the lines until we get to the CODE that we want
my @lines;
while (<FILE>)
{
push @lines, $_;
last if m/CODE = $code/;
}
# @lines now has everything from the START to the CODE. Get the last RATE in
# @lines and change its value.
my $strref = \( grep m/RATE/ @lines )[-1];
$$strref = $new_value;
# print out the lines we saved and exit the loop
print OUT @lines;
last;
}
编辑:如果你真的想要一个正则表达式,你可以使用这样的东西(未经测试):
$tx =~ s/(START \s+ ITEM \s+ = \s+ 9983.*?
BEGIN
.*?
RATE \s+ = \s+ )\d+
( (?: (?! END ) . )*
CODE \s+ = \s+ XX)
/$1$newRate$2
/sx;
添加的 (?: (?! END ) . )*
确保 RATE 和 CODE 之间的匹配不会跨越 END。但这将比非正则表达式方法慢得多。