如何使此"未初始化值的使用"警告消失?

时间:2020-03-06 14:45:03  来源:igfitidea点击:

假设我想编写一个正则表达式,将所有&lt;abc>&lt;def>&lt;ghi>标记更改为&lt;xyz>标记。 </ xyz>。这似乎是一个合理的正则表达式(忽略反引号;如果我不包括反斜线符号,则StackOverflow会出现小于号的问题):

`s!<(/)?(abc|def|ghi)>!<xyz>!g;`

而且也可以。唯一的问题是,对于打开标签,可选的$ 1变量被分配了undef,因此我收到"使用未初始化的值..."警告。

有什么优雅的方法可以解决此问题?我不想将其分成两个单独的正则表达式,一个用于打开标签,另一个用于关闭标签,因为那样的话,需要维护标签列表的两个副本,而不仅仅是一个。

编辑:我知道我可以关闭该代码区域中的警告,但我不认为这是"优雅"的。

解决方案

我们可以将第一个匹配项设为(</?),并在"替换"端摆脱硬编码的<。这样,$ 1将始终具有" <"或者" </"。可能有更优雅的解决方案来解决警告问题,但是该解决方案应该可以解决实际问题。

这是一种方法:

s!<(/?)(abc|def|ghi)>!<xyz>!g;

更新:删除了有关使用(?:pattern)的无关注释。

添加

no warnings 'uninitialized';

或者

s!<(/)?(abc|def|ghi)>! join '', '<', ||'', 'xyz>' !ge;

怎么样:

`s!(</?)(abc|def|ghi)>!xyz>!g;`

要使这两种情况下的正则表达式都捕获$ 1,请尝试:

s!<(/|)?(abc|def|ghi)>!<xyz>!g;
       ^
       note the pipe symbol, meaning '/' or ''

对于'',它将捕获'<'和'abc>'之间的',对于'',将捕获'<'和'abc>'之间的'/'。

将问号移动到捕获支架内。这样,将始终定义$ 1,但它可以是零长度的字符串。

s!<(/?)(abc | def | ghi)>!<$ {1} xyz>!g;`

唯一的区别是更改"(/)?"到 "(/?)"。我们已经确定了几种功能解决方案。我认为,这一款具有我们所要求的优雅。

I'd rather not make this into two
  separate regexs, one for opening tags
  and another for closing tags, because
  then there are two copies of the
  taglist that need to be maintained

为什么?将标记列表放入变量中,然后根据需要将变量内插到尽可能多的正则表达式中。我什至会考虑使用单个正则表达式,因为它对于复杂的正则表达式更具可读性(什么正则表达式并不复杂?)。

小心一点,因为HTML看起来比乍看之下要难一些。例如,是否要将" <abc foo ='bar'>"更改为" <xyz foo ='bar'>"?正则表达式不会。我们是否要更改" <img alt ='<abc>'>"?正则表达式将。相反,我们可能想要执行以下操作:

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。