Perl Regex匹配工作,但替换没有

时间:2012-10-15 18:50:52

标签: regex perl file-io

我已经整理了一个Perl脚本来浏览目录并匹配源中的各种键并将结果输出到文本文件。匹配操作运行良好,但最终目标是执行替换操作。 Perl脚本如下:

  #!/usr/bin/perl
  #use strict;
  use warnings;

  #use File::Slurp;

  #declare variables
  my $file = '';
  my $verbose = 0;
  my $logfile;

  my @files = grep {/[.](pas|cmm|ptd|pro)$/i} glob 'C:\users\perry_m\desktop\epic_test\pascal_code\*.*';

  #iterate through the files in input directory
  foreach $file (@files) {

     print "$file\n";

     #read the file into a single string
     open FILEHANDLE, $file or die $!;
     my $string = do { local $/; <FILEHANDLE> };

     #perfrom REGEX on this string

     ########################################################
     #fix the include formats to conform to normal PASCAL
     $count = 0;
     while ($string =~ m/%INCLUDE/g)
     {
        #%include
        $count++;
     }
     if ($count > 0)
     {
        print " $count %INCLUDE\n";
     }
     $count = 0;
     while ($string =~ m/INCLUDE/g)
     {
        #%INCLUDE;
        $count++;
     }
     if ($count > 0)
     {
        print " $count INCLUDE\n";
     }
     $count = 0;
     while ($string =~ m/(%include\s+')[A-Za-z0-9]+:([A-Za-z0-9]+.[A-Za-z]+')/g)
     {
        #$1$2;
        $count++;
     }
     if ($count > 0)
     {
        print " $count XXXX:include \n";
     }        
  }

这会根据需要生成输出,示例如下:

  C:\users\perry_m\desktop\epic_test\pascal_code\BRTINIT.PAS
   1 INCLUDE
   2 XXXX:include 
   39 external and readonly

但是,如果我更改正则表达式操作以尝试实现替换,则使用上面注释行中显示的替换操作,脚本会挂起并且永远不会返回。我想它与内存有某种关系,但我是Perl的新手。我也试图尽可能避免逐行解析文件。

示例:

  while ($string =~ s/%INCLUDE/%include/g)
  {
     #%include
     $count++;
  }

  while ($string =~ s/(%include\s+')[A-Za-z0-9]+:([A-Za-z0-9]+.[A-Za-z]+')/$1$2;/g)
  {
     #$1$2;
     $count++;
  }

编辑:简化示例

2 个答案:

答案 0 :(得分:4)

问题在于您的while循环。像

这样的循环
while ($string =~ m/INCLUDE/g) { ... }
对于目标字符串中INCLUDE的每次出现,

都会执行一次,但是

这样的子句
$string =~ s/INCLUDE/%INCLUDE;/

将一次性替换所有,并重新调整替换次数。这是一个循环

while ($string =~ s/INCLUDE/%INCLUDE;/g) { ... }

将在每个INCLUDE之后无限地添加越来越多的百分号和分号。

要查找所做的替换次数,请将所有循环更改为

$count = $string =~ s/INCLUDE/%INCLUDE;/g

答案 1 :(得分:0)

s/INCLUDE/%INCLUDE/g中的模式也会匹配替换,所以如果你在while循环中运行它,它将永远运行(直到你的内存不足)。

s///g将一次性替换所有匹配项,因此您很少需要将其置于循环中。同样适用于m//g,如果将它放在列表上下文中,它将在一个步骤中进行计数。