0

我需要替换以下字符串:

<book name=""
      author="">

<magazine>

我下面的代码不起作用:

sub substitution
{
my $find = "book name\=\"\"\nauthor\=\"\"";
my $replace = "magazine";
{  
local @ARGV = ("$_[0]");
local $^I = '.bac';

while( <> )
{
  if( s/$find/$replace/ig ) {
     print;
                            }

else {
     print;
     }
} //while
}
4

4 回答 4

3

就像 Brian 已经说过的,使用 XML 解析器。这是一个使用 XML::LibXML 并使用 setNodeName(用于更改元素名称)和 removeAttributes(用于删除两个属性)进行 DOM 操作的示例:

use strict;
use XML::LibXML;

my $doc = XML::LibXML->new->parse_string(<<EOF);
<books>
 <book name=""
       author="">
  <chapter>something</chapter>
 </book>
 <book name=""
       author="">
  <chapter>something</chapter>
 </book>
</books>
EOF

for my $book_node ($doc->findnodes('//book')) {
    $book_node->setNodeName('magazine');
    $book_node->removeAttribute($_) for qw(name author);
}

print $doc->serialize;

另一种可能性是在这里使用 xslt ......

于 2013-07-10T09:03:26.430 回答
1

出于有据可查的原因,我强烈建议您使用XML 解析器而不是正则表达式。

查看Comprehensive Perl Archive Network以获得更合适的库。

于 2013-07-10T08:55:47.983 回答
1

如果您想要快速简单的解决方案(为什么还要使用 Perl?),那么只需使用

my $find = qr|<book name=""\s+author="">|s;
my $replace = '<magazine>';

而且当您想跨多行替换某些内容时,您不能逐行读取,而是应该以标量形式 slurp 文件(如果您的文件足够小以适合内存)

local $/; # undefines input lines separator
# open your file with open(FILE, '<', $filename);
my $text = <FILE>;
$text =~ s/$find/$replace/g;
# do with $text what you want now, print it or anything
# don't forget to close your FILE

这既快又脏,但效果很好。如果您的文件不适合内存,或者您想确保一切正常,请使用 XML 解析器,但请记住

  1. 不要使用 XML::Simple,它坏了,真的
  2. 对于大文件,您需要流 XML 解析器,例如XML::Parser
于 2013-07-10T09:09:33.437 回答
1

使用xsh,一个围绕XML::LibXML的包装器:

open file.xml ;
for //book[@name="" and @author=""] {
    rename magazine . ;
    delete @* ;
}
save :b ;
于 2013-07-10T09:09:40.687 回答