假设我想写一个正则表达式,将所有<abc>
,<def>
和<ghi>
标签更改为<xyz>
标签..我还想更改他们的关闭标签</xyz>
。这似乎是一个合理的正则表达式(忽略反引号;如果我不包含它们,StackOverflow会遇到小于符号的问题):
`s!<(/)?(abc|def|ghi)>!<${1}xyz>!g;`
它也有效。唯一的问题是,对于打开标签,可选的$ 1变量被赋予undef,因此我得到一个“使用未初始化的值...”警告。
解决这个问题的优雅方法是什么?我宁愿不把它变成两个单独的正则表达式,一个用于打开标签,另一个用于关闭标签,因为那时需要维护两个标签列表副本,而不是一个。
编辑:我知道我可以在代码的这个区域关闭警告,但我不认为这是“优雅的”。
答案 0 :(得分:10)
将问号移到捕获括号内。这样,$ 1将始终定义,但可能是零长度字符串。
答案 1 :(得分:2)
怎么样:
`s!(</?)(abc|def|ghi)>!${1}xyz>!g;`
答案 2 :(得分:1)
你可以让你的第一场比赛成为(&lt; /?),并摆脱硬编码的&lt;在“替换”方面。然后$ 1总是有“&lt;”或“&lt; /”。可能有更优雅的解决方案来解决警告问题,但这个解决方案应该处理实际问题。
答案 3 :(得分:1)
这是一种方式:
s!<(/?)(abc|def|ghi)>!<$1xyz>!g;
更新:删除了有关使用(?:pattern)
的无关评论。
答案 4 :(得分:1)
s!<(/?)(abc|def|ghi)>!<${1}xyz>!g;
唯一的区别是改变“(/)?”至 ”(/?)”。您已经确定了几个功能解决方案。我觉得这个有你要求的优雅。
答案 5 :(得分:0)
要使正则表达式捕获$ 1,请尝试:
s!<(/|)?(abc|def|ghi)>!<${1}xyz>!g;
^
note the pipe symbol, meaning '/' or ''
对于''这将捕捉''之间的''&lt;'和'abc&gt;',以及'',捕捉'/'之间'&lt;'和'abc&gt;'。
答案 6 :(得分:0)
我宁愿不把它变成两个 单独的正则表达式,一个用于打开标签 另一个用于关闭标签,因为 然后有两份副本 需要维护的标签列表
为什么呢?将您的标记列表放入变量并将该变量插入到任意数量的正则表达式中。我认为这甚至只有一个正则表达式,因为它具有复杂的正则表达式更具可读性(并且正则表达式并不复杂?)。
答案 7 :(得分:0)
要小心,因为HTML看起来有点难以乍一看。例如,您要更改“&lt; abc foo ='bar'&gt;”到“&lt; xyz foo ='bar'&gt;”?你的正则表达式不会。你想改变“&lt; img alt ='&lt; abc&gt;'&gt;”吗?正则表达式会。相反,你可能想要做这样的事情:
use HTML::TreeBuilder;
my $tree=HTML::TreeBuilder->new_from_content("<abc>asdf</abc>");
for my $tag (qw<abc def ghi>) {
for my $elem ($tree->look_down(_tag => $tag)) {
$elem->tag('xyz');
}
}
print $tree->as_HTML;
这使您不必自己解决HTML的繁琐问题。
答案 8 :(得分:-1)
添加
no warnings 'uninitialized';
或
s!<(/)?(abc|def|ghi)>! join '', '<', ${1}||'', 'xyz>' !ge;