【问题标题】:Why does this regex in perl work for one word but not another?为什么 perl 中的这个正则表达式适用于一个单词而不适用于另一个单词?
【发布时间】:2017-08-24 18:26:45
【问题描述】:

我是 perl 新手,所以如果我的问题看起来很明显,请原谅。我制作了一个小的 perl 脚本,它只检查自身以提取我正在寻找的特定子字符串,并且得到了我无法解释的结果。这是脚本:

use 5.006;
use strict;
use warnings;
use File::Find;

my @files;
find( 
    sub { push @files, $File::Find::name unless -d; }, 
    "."
);

my @filteredfiles = grep(/.pl/, @files);

foreach my $fileName (@filteredfiles)
{
open (my $fh, $fileName) or die "Could not open file $fileName";

while (my $row = <$fh>)
{
    chomp $row;
    if ($row =~ /file/)
    {
        my ($substring) = $row =~ /file\(([^\)]*)\)/;
        print "$substring\n" if $substring;
    }
}

close $fh;
}

# file(stuff)
# directory(stuff)

现在,当我运行它时,我得到以下输出:

stuff
[^\
  1. 为什么会乱序打印行?由于“stuff”行出现在文件的后面,不应该稍后打印吗?

  2. 为什么第二行打印错误?它应该是“\(([^\”。它缺少前 3 个字符。

  3. 如果我将正则表达式更改为以下内容:/directory\(([^\)]*)\)/,我将没有输出。唯一的区别是单词。它应该找到第二条评论。这是怎么回事?

【问题讨论】:

  • 您是否也更改了围绕它的if 块的条件?
  • 对我来说,这只是打印stuff,而不是[^\ 。由于file( 之间的反斜杠,正则表达式无法匹配自身!您在同一目录中是否有任何其他文件名包含 pl?可能是同一脚本的先前版本?
  • 好的,这是一个显而易见的答案,我在过去的一个小时里一直在努力反对。不,我忘了更改 if 语句。谢谢你。至于第二条评论,不,我在目录中没有任何其他 pl 文件。
  • 请注意,/.pl/ 匹配包含任何字符后跟pl 的任何单词,例如单词example. 不是文字点,而是匹配任何(非换行符)字符。正则表达式未锚定为仅在末尾匹配。您可能打算 /\.pl$/ 过滤文件名。由于字符序列[^\ 相当独特,可能它们来自先前版本脚本的隐藏备份文件?
  • 我上面评论中的if (...) 将捕获存储在$substr 变量中,然后在{ ... }if 分隔的范围内可用。所以是的,你在$substr 中有'catch'。你是这个意思吗?查看@Sinan 的完整答案。

标签: regex perl


【解决方案1】:
  1. use 5.006 如果你刚开始学习 Perl 有点奇怪......那是一个古老的版本。

  2. 您不应该在当前目录下的所有位置构建一个可能很大的所有文件列表,然后对其进行过滤。相反,只将您想要的文件推送到列表中。

  3. 尤其是使用转义的元字符时,正则表达式模式很快就会变得难以阅读,因此请使用/x 修饰符在这些模式中插入一些空格。

  4. 您不必匹配两次:只需同时检查和捕获即可。

  5. 如果open 失败,请在错误消息中包含原因。

  6. 您上面的第二个问题没有意义。您似乎希望您的模式与文字字符串 file\(([^\)]*)\)/ 匹配,但事实并非如此。


use strict;
use warnings;
use File::Find;

my @files;

find(
    sub {
        return if -d;
        return unless / [.] pl \z/x;
        push @files, $File::Find::name;
    },
    '.',
);

for my $file ( @files ) {
    open my $fh, '<', $file
        or die "Could not open file $file: $!";

    while (my $line = <$fh>) {
        if (my ($substring) = ($line =~ m{ (?:file|directory) \( ([^\)]*) \) }x)) {
            print "$substring\n";
        }
    }

    close $fh;
}

# file(stuff)
# directory(other)

输出:

stuff
other

【讨论】:

  • 感谢您的建议。我会记住这些。奇怪的是,使用 Padre IDE,/x 之后的所有内容都不再被识别为正确的语法。
猜你喜欢
  • 2011-05-01
  • 2019-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多