通过捕获搜索和替换正则表达式

时间:2013-08-08 23:11:12

标签: regex perl

我有一个很长的文本文件,我希望大部分保持不变,但某些短语需要翻译。这不是一个干净的搜索和替换...例如,我需要更改此次发生的每一次......

lis r3, ha16(aLabel)

......进入这个:

lis r3, aLabel@ha

即。我需要找到整个ha16(aLabel),从中捕获aLabel(可以是任何标识符文本,直到终止端paren),然后发出已捕获文本的替换,后跟{{ 1}}。

我找到了很多关于perl搜索和替换的例子,但是我没有遇到任何我需要的东西,其他提到'perl'和'capture'的帖子似乎并没有解决我的问题问题...或者他们可能会这样做而且我太愚蠢而无法实现它。

3 个答案:

答案 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}}在我的示例文本上。

Live DEMO.

答案 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;
}

使用?摆脱贪婪,.匹配几乎任何字符,+表示一个或多个。