我有一个很长的文本文件,我希望大部分保持不变,但某些短语需要翻译。这不是一个干净的搜索和替换...例如,我需要更改此次发生的每一次......
lis r3, ha16(aLabel)
......进入这个:
lis r3, aLabel@ha
即。我需要找到整个ha16(aLabel)
,从中捕获aLabel
(可以是任何标识符文本,直到终止端paren),然后发出已捕获文本的替换,后跟{{ 1}}。
我找到了很多关于perl搜索和替换的例子,但是我没有遇到任何我需要的东西,其他提到'perl'和'capture'的帖子似乎并没有解决我的问题问题...或者他们可能会这样做而且我太愚蠢而无法实现它。
答案 0 :(得分:3)
你可以这样做:
#!/usr/bin/perl
use strict;
use warnings;
my $text = 'lis r3, ha16(L_.str10) some more text blah lis r3, lo16(identifier) some more text blah lis r3, ot16(identifier)';
$text =~ s/(\w{2})\d{2}\(([\w\.]+)\)/$1 eq 'lo' ? $2 . '@l' : $2 . '@' . $1/gie;
print $text;
也可以写成:
#!/usr/bin/perl
use strict;
use warnings;
while (<DATA>) {
s/(\w{2})\d{2}\(([\w\.]+)\)/$1 eq 'lo' ? $2 . '@l' : $2 . '@' . $1/gie;
#you can also print out the result of the replacement.
#print $_;
}
__DATA__
lis r3, ha16(L_.str10)
some more text blah lis r3, lo16(identifier)
some more text blah lis r3, ot16(identifier)
简单来说,e
修饰符允许您使用可用于替换模式的正则表达式右侧的代码。 For a more detailed explanation you can read this question.
在这个例子中,我使用(\w{2})\d{2}
来匹配括号内的标签之前的扩展名,并将2个字母分组供以后使用,并使用([\w\.]+)
表示任何字母数字字符加上下划线和点,以匹配你的标签。
在右边,我正在做一个三元运算符来定义扩展名:
$1 eq 'lo' ? $2 . '@l' : $2 . '@' . $1
如果第一个元素是2个字母等于lo
则使用@l
如果没有,则使用@extension
的2个字母作为实例@ha
或{{ 1}}在我的示例文本上。
答案 1 :(得分:2)
我认为这可以改进为一行,但我就是这样做的:
$val = "lis r3, ha16(L_.str10)";
if ($val =~ /ha16\((.*?)\)/) {
# $1 now contains the extracted text
$capture = $1;
$val =~ s/ha16\(.*?\)/$capture\@ha/gi;
}
所涉及的正则表达式的解释:
ha16\((.*?)\)
ha16\(
基本上表示“以ha16(
开头的任何文字”。此后(
已转义
它是一个正则表达式关键字
(.*?)
()
意味着“捕获与此内部模式匹配的所有内容。
.*?
表示“匹配零或更多(即*
)任何字符(即.
)
?
意味着非贪婪地执行
\)
说“一旦你达到这一点,就停止匹配”(这是因为
我们使用的非贪婪?
替换:
s/ha16\(.*?\)/$1\@ha/gi
此格式的任何内容:s/<something>/<something>/
都会告诉perl进行查找
并替换。 $1
是第一组括号中的匹配(如果有的话)
多一个,我们会有$2
等等。最后的gi
表示要替换
GLOBALLY(在替换第一场比赛后不要停止),并且执行case-INSENSITIVE。
答案 2 :(得分:2)
像...这样的东西。
use strict;
use warnings;
while (<>) {
s/ha16\((.+)\)/$1\@ha/gi;
print;
}
或者更好的是,使用映射表示多次出现变化。
my %map = (
ha => '@ha',
hi => '@hi',
lo => '@l'
);
while (<>) {
s/(\w{2})16\((.+)\)/$2$map{$1}/gi;
print;
}
使用?
摆脱贪婪,.
匹配几乎任何字符,+
表示一个或多个。