【问题标题】:perl regex: searching thru entire line of fileperl 正则表达式:搜索整行文件
【发布时间】:2016-04-06 04:03:55
【问题描述】:

我是一个正则表达式新手,我正在尝试使用正则表达式从文本文件中返回日期列表。日期采用 mm/dd/yy 格式,例如,对于年份,“1955”将是“55”。我正在尝试将所有条目从 50 年返回到 99 年。

我相信我遇到的问题是,一旦我的正则表达式在一行上找到匹配项,它就会停在那里并跳转到下一行而不检查该行的其余部分。例如,我在文本文件的一行中有日期 12/12/12、10/10/57、10/09/66,它只返回 10/10/57。

到目前为止,这是我的代码。任何提示或提示?谢谢

open INPUT, "< dates.txt" or die "Can't open input file: $!";
while (my $line = <INPUT>){
    if ($line =~ /(\d\d)\/(\d\d)\/([5-9][0-9])/g){
        print "$&\n"  ;
        }
}

【问题讨论】:

  • 请显示您输入的行。
  • 如下:12/12/12 10/10/57 10/09/66
  • 在您的问题中显示您的文件(准确)的外观,这可能非常有用。

标签: regex perl


【解决方案1】:

关于您的代码的几点说明

  • 必须始终 use strictuse warnings 'all' 在所有 Perl 程序的顶部

  • 你应该更喜欢词法文件句柄和open的三参数形式

  • 如果您的正则表达式模式包含文字斜杠,那么最清楚的是使用非标准分隔符,这样它们就不需要转义

  • 虽然最近的 Perl 版本已经修复了这个问题,但使用 $&amp; 时性能会受到很大影响,因此最好避免它,至少现在是这样。将捕获括号放在整个模式周围,并改用$1

这个程序会按照你的要求做

use strict;
use warnings 'all';

open my $fh, '<', 'dates.txt' or die "Can't open input file: $!";

while ( <$fh> ) {
    print $1, "\n" while m{(\d\d/\d\d/[5-9][0-9])}g
}

输出

10/10/57
10/09/66

【讨论】:

    【解决方案2】:

    您正在打印$&amp;,只要遇到任何新匹配,它就会更新。

    但是在这种情况下,您需要存储所有以前的匹配项和更新的匹配项,因此您可以使用数组来存储所有匹配项。

    while(<$fh>) {
      @dates = $_ =~ /(\d\d)\/(\d\d)\/([5-9][0-9])/g;
      print "@dates\n" if(@dates);
    }
    

    【讨论】:

      【解决方案3】:

      您只需将“if”更改为“while”,正则表达式就会从中断处开始;

      open INPUT, "< a.dat" or die "Can't open input file: $!";
      while (my $line = <INPUT>){
          while ($line =~ /(\d\d)\/(\d\d)\/([5-9][0-9])/g){
              print "$&\n"  ;
          }
      }
      # Output given line above
      # 10/10/57
      # 10/09/66
      

      您还可以将整个日期捕获到一个捕获变量中,并使用不同的正则表达式分隔符来保存转义斜杠:

      while ($line =~ m|(\d\d/\d\d/[5-9]\d)|g)  {
          print "$1\n" ;
      }
      

      ...但这也许是个人喜好问题。

      【讨论】:

      • 非常感谢!我确信我的正则表达式有问题,我什至没有想到我需要另一个 while 循环。
      【解决方案4】:

      您也可以使用 map 来获取 50 到 99 的年份范围并存储在数组中

      open INPUT, "< dates.txt" or die "Can't open input file: $!";
      @as = map{$_ =~ m/\d\d\/\d\d\/[5-9][0-9]/g} <INPUT>;
      $, = "\n";
      print @as;
      

      【讨论】:

        【解决方案5】:

        另一种解决方法是删除您不想要的日期。

        $line =~ s/\d\d\/\d\d\/[0-4]\d//g;
        print $line;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多