简体   繁体   English

Perl正则表达式匹配有效,但替换无效

[英]Perl Regex match works, but replace does not

I have put together a Perl script to go through a directory and match various keys in the source and output the results to a text file. 我整理了一个Perl脚本来遍历目录,并匹配源代码中的各种键,然后将结果输出到文本文件中。 The match operation works well, however the end goal is to perform a replace operation. 匹配操作效果很好,但是最终目标是执行替换操作。 The Perl script is as follows: 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";
     }        
  }

This produces output as desired, an example is below: 这将根据需要产生输出,下面是一个示例:

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

However if I change the regex operations to try and implement a replace, using the replacement operation shown in the commented lines above, the scripts hangs and never returns. 但是,如果我更改了正则表达式操作以尝试实现替换,则使用上面注释行中显示的替换操作,脚本将挂起并且永远不会返回。 I imagine it is somehow related to memory, but I am new to Perl. 我以为它与内存有关,但是我对Perl还是陌生的。 I was also trying to avoid parsing the file by line if possible. 我还试图避免如果可能的话按行分析文件。

Example: 例:

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

and

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

Edit: simplified the examples 编辑:简化示例

The problem is with your while loops. 问题出在您的while循环上。 A loop like 像这样的循环

while ($string =~ m/INCLUDE/g) { ... }

will execute once for each ocurrence of INCLUDE in the target string, but a subtitution like 将针对目标字符串中每次出现INCLUDE都执行一次,但是类似

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

will make all of the replacement in one go and retuen the number of replacements made. 将一次性完成所有替换,并重新获取替换的数量。 So a loop 如此循环

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

will endlessly add more and more percentage signs before and semicolons after every INCLUDE . 在每一个INCLUDE之前和分号后面都会不断添加越来越多的百分号。

To find the number of replacements made, change all your loops like this to just 要查找更换的数量,请将所有循环更改为

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

the pattern in s/INCLUDE/%INCLUDE/g will match the replacement also, so if you're running it in a while loop it will run forever (until you run out of memory). s/INCLUDE/%INCLUDE/g中的模式也将与替换匹配,因此,如果您在while循环中运行它,它将永远运行(直到内存不足)。

s///g will replace all matches in a single shot so you very rarely will need to put it in a loop. s///g可以一次性替换所有比赛,因此您很少需要将其放在循环中。 Same goes for m//g , it will do the counting in a single step if you put it in list context. m//g也一样,如果将其放在列表上下文中,它将一步完成计数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM