【问题标题】:Perl return match string ignoring the ending delimiter if it existsPerl 返回匹配字符串,如果存在则忽略结束分隔符
【发布时间】:2014-03-09 06:38:22
【问题描述】:

我正在尝试在 perl 中进行模式匹配,在其中我检查从文件中读取的行的开头是否存在“非空白字符”,并返回第一个匹配的单词。

问题是,有时我的单词会以':'结尾,有时我不会。

例如:

假设我有一个包含以下内容的文件。有时带有替代内容。该文件会自动填充。

some0 Loren Posem:is some color::and some foo bar with 1023:4632
      some more content added to the file
some3 Loren Posem:is some color::and some foo bar with 1023:4632
      some more content added to the file

替代内容:

some1: Loren Posem:is some will be different with some number 5423:32
      some more content added to the file
some3: Loren Posem:is some will be different with some number 5423:32
      some more content added to the file

现在我只想从这个文件中提取第一个单词。但是如果文件有替代内容,我仍然只想要第一个单词忽略尾随的':'。

我这里只需要模式匹配部分。 这是我到目前为止所得到的。

foreach ... 
    if  (/^(\S+):/) { 
        print $1;
    }

/* 如果我使用上述模式匹配,我将从替代内容中获取第一个单词,即 some1 和 some3 忽略尾随的“:”但是当我有原始内容时,$1 不匹配。 */

但是如果我使用

foreach ... 
    if  (/^(\S+)/) { 
        print $1;
    }

/* 现在替代内容将不匹配。 */

这里有什么提示吗?

【问题讨论】:

    标签: regex perl pattern-matching


    【解决方案1】:

    贪婪匹配排除空格和冒号:

    while (<DATA>) {
        if  (/^([^:\s]+)/) { 
            print "$1\n";
        }
    }
    
    __DATA__
    some0 Loren Posem:is some color::and some foo bar with 1023:4632
          some more content added to the file
    some3 Loren Posem:is some color::and some foo bar with 1023:4632
          some more content added to the file
    Alternate content:
    
    some1: Loren Posem:is some will be different with some number 5423:32
          some more content added to the file
    some3: Loren Posem:is some will be different with some number 5423:32
          some more content added to the file
    

    【讨论】:

    • 感谢您的解决方案和解释。
    【解决方案2】:

    如果您要处理大量数据,splitting(并设置 split 的 LIMIT)获取第一个单词可以提供比捕获正则表达式显着的性能优势,在这种情况下:

    foreach ... 
        if (  my $firstWord = ( split /[:\s]/, $_, 2 )[0] ) {
        print $firstWord, "\n";
    }
    

    Benchmark:

    use strict;
    use warnings;
    use Benchmark qw/cmpthese/;
    
    my @data = <DATA>;
    
    sub _split {
        for (@data) {
            if ( my $firstWord = ( split /[:\s]/, $_, 2 )[0] ) {
                #print $firstWord, "\n";
            }
        }
    }
    
    sub _regex {
        for (@data) {
            if ( my ($firstWord) = /^([^:\s]+)/ ) {
                #print $firstWord, "\n";
            }
        }
    }
    
    cmpthese(
        -5,
        {
            _split => sub { _split() },
            _regex => sub { _regex() }
        }
    );
    
    __DATA__
    some0 Loren Posem:is some color::and some foo bar with 1023:4632
    some3 Loren Posem:is some color::and some foo bar with 1023:4632
    some1: Loren Posem:is some will be different with some number 5423:3
    some3: Loren Posem:is some will be different with some number 5423:32
    

    输出(表中的时间越短):

               Rate _regex _split
    _regex 396843/s     --   -12%
    _split 450546/s    14%     --
    

    但是,您可能会发现正则表达式更具可读性。

    希望这会有所帮助!

    【讨论】:

    • 当我打印 $1 时,我仍然看到尾随的“:”,但我不想要那个 ':'
    • @devgp - 是的,并且已通过建议使用 split 而不是捕获正则表达式进行了修改。
    • 谢谢。很好的解释
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-04
    • 1970-01-01
    相关资源
    最近更新 更多