正则表达式替换左括号

时间:2013-05-08 02:36:04

标签: regex perl parentheses

作为解析脚本的一部分,我正在尝试转换这样的字符串:

<a href="http://www.web.com/%20Special%20event%202013%20%282%29.pdf">

<a href="http://www.web.com/%20Special%20event%202013%20(2).pdf">

右括号的正则表达式正常

perl -i -pe "s~(href\=\/?[\"\']\.\.\/$i\-(?:(?!%29).)*)%29([^\"\']*[\"\'])~\1)\2~g" "$pageName".html

给我

    <a href="http://www.web.com/%20Special%20event%202013%20%282).pdf">

问题与左括号的等效正则表达式相矛盾:

perl -i -pe "s~(href\=\/?[\"\']\.\.\/$i\-(?:(?!%28).)*)%28([^\"\']*[\"\'])~\1(\2~g" "$pageName".html                                

只返回两组之间没有任何内容:

<a href="http://www.web.com/%20Special%20event%202013%202%29.pdf">

逃避(用反斜杠替换(或两个)没有效果。如果我将它包装在其他一些字符中(比如〜\ 1#(#\ 2~g),括号仍然消失(给我%20) ## 2%29)。

然而,如果在绝望中我将7个括号添加到替换中,它就可以工作。

perl -i -pe "s~(href\=\/?[\"\']\.\.\/$i\-(?:(?!%28).)*)%28([^\"\']*[\"\'])~\1(((((((\L\2~g" "$pageName".html

输出

<a href="http://www.web.com/%20Special%20event%202013%20(2%29.pdf">

有人可以理解这一点。

3 个答案:

答案 0 :(得分:3)

以下可能会有所帮助或至少提供一些方向。它适用于Perl版本10及更高版本。

use strict;
use warnings;
use v5.10.0; # For regex \K

use URI::Escape;

my $string = '<a href="http://www.web.com/%20Special%20event%202013%20%282%29.pdf">';
$string =~ s/.+2013%20\K([^.]+)(?=\.pdf)/uri_unescape($1)/e;
print $string;

输出:

<a href="http://www.web.com/%20Special%20event%202013%20(2).pdf">

将足够的日期和空格(%20)作为锚,然后使用\K来* K * eep全部。然后捕获URI编码的文本,稍后将其解码并用作替换文本。

答案 1 :(得分:0)

我在理解你的正则表达式时遇到了一些问题,但这可能会有效:

 perl -pe "s~(href\s*=\s*\"[^\"]*)%28(.*?)%29~\$1(\$2)~g" input

答案 2 :(得分:0)

您拥有的模式与您显示的字符串不匹配。它匹配看起来像

的东西
<a href=/"../$i-xxxxxxxxxxxxxxx%29xxxxxxxxxx">

带有文字点,以及$i包含的内容。

另外,关于你替换的几点:

  • 不要转义不需要转义的字符。可能需要一些经验才能知道你需要逃避哪些字符,但使用~作为分隔符的主要目的是避免在正则表达式中转义斜杠,所以至少你可以避免这种情况。

  • 请勿在替换字符串中使用\1\2等。 Perl非常努力地完成这项工作,但通常在Perl中,这些序列意味着插入字符\x01\x02。使用$1$2

所以你的正则表达式可以写成

s~(href=/?["']\.\./$i-(?:(?!%29).)*)%29([^"']*["'])~$1)$2~;

但是它仍然没有“正常工作”你给的字符串,这看起来像

<a href=/"../$i-xxxxxxxxxxxxxxx%282%29xxxxxxxxxx">

再次,包含$i中的任何内容。我完全不了解href属性值之前的可选斜杠:它是无效的HTML。

但是,使用第一个正则表达式匹配的字符串,你的第二个正常工作,正确替换开括号,所以我无法猜出问题可能是什么。

通常无需验证整个字符串。你可以只替换你感兴趣的部分。所以我会写一些类似

的东西
s/(href="[^"]+)%28(\d+)%29(\.pdf")/$1($2)$3/;

在您给出的字符串上工作正常,并立即替换打开和关闭括号。