如何在perl中有效地搜索/替换文件中的某些字符串?

时间:2011-11-11 17:20:09

标签: xml perl xml-parsing

我的文件如下:

<MAIN>  
  <SUB_MAIN>one</SUB_MAIN>  
  <VER>version#</VER>  
  (OTHER STUFF...)  
  <LOCATION>PATH</LOCATION>  
</MAIN>

<MAIN>  
  <SUB_MAIN>two</SUB_MAIN>  
  <VER>version#</VER>  
  (OTHER STUFF...)  
  <LOC>PATH</LOC>  
</MAIN>

我想要做的是搜索SUB_MAIN的值,让我们说一个,如果找到它,则查找LOCATION的值。转到该位置执行某些同步从中获取新版本并更新VER信息。

我当前的代码有三个循环并且很难看。骨架是这样的:

$value = "one|two|three";

# for each line in file
while ($line < @FileDat) {

    # see if it is a sub module?   
    if ( $line =~ /\<SUB_MAIN\>$value\<\/SUB_MAIN\>/ ) 
    {   
       $found_it = 0;

        while (!$found_it) 
        {       
            $lineNum++;     
            if ( $FileDat[$lineNum] =~ /\<VER\>\d+\<\/VER\>/ ) 
            {
                $currIndex = $lineNum;

                while(1)
                {
                   $lineNum++;
                   if ( $FileDat[$lineNum] =~ /\<LOC\>(.+)\<\/LOC\>/ ) 
                    {   #DO SOME STUFF...
                        $found_it = 1;
                        last;
                    }
                }               
                        #replace version #
                $FileDat[$currIndex] = "    <VER>$latestChangeList</VER>\n";
            }
        }
    }
    $lineNum++;
}

# write the modified array to new file
print NEWCFGFILEPTR @FileDat;

close(OPEN_FILES);

我怎样才能做得更好?
谢谢。

3 个答案:

答案 0 :(得分:1)

使用XML::Simple。没有必要重新发明轮子,除非你打算让它变得更好,我非常怀疑这是你的任务。

答案 1 :(得分:1)

实际上,使用XML解析器比仅使用XML模块要复杂一些,因为你所拥有的并不是格式良好的XML。格式良好的XML文件将具有单个根,因此所有MAIN元素都将包含在单个元素中。

有一种相对简单的伪造方法,即将您的文件(在XML实体中引用)包装在适当的高级元素中。

另外,在你的示例数据中,第一个MAIN中有一个LOCATION元素,第二个MAIN中有一个LOC元素,我认为它是一个cut'n粘贴错误。

这是一种使用XML :: Twig的方法,它可以处理任何大小的输入文件(包括大到适合内存),并输出到标准输出。

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

binmode( STDOUT, ':utf8'); # if your input file is in UTF-8

my $file= shift @ARGV;
# wrap the content of the file in <data>...</data> so it becomes well-formed XML
my $xml= qq{<?xml version="1.0"?>
            <!DOCTYPE data [ <!ENTITY file SYSTEM "$file">]>
            <data>&file;</data>
           };

XML::Twig->new( twig_handlers => { MAIN => \&main },
                keep_spaces => 1,
              )
         ->parse( $xml);

exit;

sub main
  { my( $t, $main)= @_;
    my $location= $main->field( 'LOCATION');
    $main->set_field( VER => get_version( $location));
    $main->print;
    $main->purge; # if the file is big and you want to free the memory
  }

sub get_version
  { my( $location)= @_;
    return "new.version.$location"; # the real code might be different!
  }

如果输入文件不是UTF-8,则可能需要更改包装器以将正确的编码添加到XML声明中。如果使用的是纯ASCII,那么你就是好的(如果添加了UTF-8字符,它仍然可以工作)。

如果您不想使用XML :: Twig,则相同的技术适用于创建可由XML :: Simple或您要使用的任何其他模块读取的正确XML。

答案 2 :(得分:0)

您有一个XML文件。不要使用正则表达式(通常被认为是坏主意)解析它,而是尝试使用现有的XML解析模块之一,如XML::Parser。还有许多其他类似的模块,您可以通过searching for xml on search.cpan.org找到它,但这是一个很好的模块。