如何对Perl钻石操作员返回的数据进行多行匹配

时间:2009-12-22 20:25:01

标签: regex perl

是否有一些技巧可以与<>进行多行正则表达式匹配,并循环它们?对于以\n作为换行符分隔符的文件运行时,此示例不会导致匹配:

while (<> =~ m/\n./) {
  print($.);
}

我需要知道while循环内匹配开始的行,如示例所示。

目标是找到所有小于75个字符的行,后面跟一个以空格开头的行(标准的vCard分割长行的方式):

while (<> =~ m/(^|\n).{0,74}\n /)

3 个答案:

答案 0 :(得分:6)

你在那个正则表达式中要做什么?看起来你试图找到一个换行符后面跟着至少一个字符的任何情况,然后这会导致你打印出符合该标准的行号($.)。

如果你不介意我的问题,这里的目的是什么?

在任何情况下,请参阅此文章,以清楚地讨论多行匹配:Regexp Power

在转移到SO后编辑:如果您真正想要的是找到少于75个字符的行和以空格开头的下一行,我不会不要使用一个正则表达式。该描述指出了一种更简单,更清晰(我认为)的解决方案:(1)过滤掉少于75个字符的所有行(length函数对此有利)。对于剩余的行,(2)检查下一行是否以空格开头。这为您提供了清晰的逻辑和易于编写的正则表达式。

回答关于获得“下一行”的问题。反过来想想:你想检查每个 next 行,但前提是之前的行少于75个字符。那怎么样:

my $prev = <>; # Initialize $prev with the first line

while (<>) {
    # Add 1 to 75 for newline or chomp it perhaps?
    if (length $prev < 76) {
        print "$.: $_" if $_ =~ m/^\s/;
    }
    $prev = $_;
}

(请注意,我对vCard格式一无所知,并且\s比字面上的“单个空格”更广泛。所以您可能需要调整该代码以更好地适应您的问题。)

答案 1 :(得分:5)

您是否记得通过将$/设置为空字符串或未定义的值来将句柄置于多行模式?

以下程序可以满足您的需求:

#! /usr/bin/perl

use warnings;
use strict;

$/ = "";

*ARGV = *DATA;

while (<>) {
  while (/^(.{0,75}\n(^[ \t].{1,75}\n)*)/mg) {
    my $vcard = $1;

    $vcard =~ s/\r?\n[ \t]//g;

    print $vcard;
  }
}

__DATA__
DESCRIPTION:This is a long description that exists on a long line.
DESCRIPTION:This is a long description
  that exists on a long line.
DESCRIPTION:This is a long descrip
 tion that exists o
 n a long line.

输出:

$ ./try
DESCRIPTION:This is a long description that exists on a long line.
DESCRIPTION:This is a long description that exists on a long line.
DESCRIPTION:This is a long description that exists on a long line.

答案 2 :(得分:3)

你有一个文件与vCards混合的任意文字?

如果您拥有的是一堆vCard文件并且想要解析它们,那么有一些vCard parsing modules on CPAN

例如,请参见Text::vCard,特别是Text::vCard::Addressbook

关于,

while (<> =~ m/\n./) {
  print($.);
}

这确实不匹配任何东西,因为输入是逐行读取的简单事实意味着在换行符之后$_中没有任何内容。

如果,每行短于76个字符后,永远不会超过单个延续行,以下内容可能符合以下要求:

#!/usr/bin/perl

use strict; use warnings;

for 
( 
    my $this = <>, my $next = <>;
    defined ($next = <>);
    close ARGV if eof
) 
{
    printf "%s : %d\n", $ARGV, $. - 1 if 76 > length $this and $next =~ /^ /;
}