在多行上匹配perl正则表达式

时间:2014-04-10 01:02:58

标签: regex perl

好的我还有另一个问题需要帮助我需要使用perl在txt文件中收集地址,我有一个地方可以从文件中的每个单独的票据中获取地址。我的问题是地址延伸的多行。我可以让它抓住第一线,但无论我做什么,它都不会抓住下一条线。

示例文本文件

NAME     Sprinkle, Jonathan U  ADDRESS     16887 36 St NW    
                                           Calgary, AB T8O 0B0

带公寓的示例文本文件

NAME     Nguyen, Michael S     ADDRESS     100A  
                                           8447 149 Ave NW    
                                           Sherwood Park, AB T6J    0Z0

我需要能够处理带有公寓号码的地址以及没有公寓号码的房子

到目前为止我的代码(这只能抢到第一行):

if (/ADDRESS/){
    my @arr = /ADDRESS\s*\S*\s\S*\s\S*\s\S*\s*\n\s*\S*/g or next;
    print "$_\n" for @arr;
}

这给出的输出是: ADDRESS 16887 36 St NW 然后它在这里打印一个换行符,而没有剩下的信息

3 个答案:

答案 0 :(得分:1)

由于my @arr = /ADDRESS\s*\S*\s\S*\s\S*\s\S*\s*\n\s*\S*/g or next;每次迭代,您只得到一行,您将数组设置为等于上一次模式匹配。您需要使用push附加到该行,如下所示:

数据

NAME     Sprinkle, Jonathan U  ADDRESS     16887 36 St NW    Calgary, AB T8O 0B0
NAME     Nguyen, Michael S     ADDRESS     100A  8447 149 Ave NW    Sherwood Park, AB T6J    0Z0

<强> EX:

use strict;
use warnings;

my @addresses;
while ( $test =~ /ADDRESS\s*([A-Za-z0-9,[:blank:]]+)/gxm ) {
    push @addresses, $1 ;
}

答案 1 :(得分:1)

OP注意:如果您提供的不仅仅是一条数据记录,它将有助于解决此类问题。

但是,当我们合并两个数据示例时,NAME和ADDRESS字段显然是垂直对齐的。这提供了一种相当简单的解析方法,因为我们基本上只需要匹配一个精确的正则表达式:

NAME     Sprinkle, Jonathan U  ADDRESS     16887 36 St NW    
                                           Calgary, AB T8O 0B0
NAME     Nguyen, Michael S     ADDRESS     100A  
                                           8447 149 Ave NW    
                                           Sherwood Park, AB T6J    0Z0

使用它作为基线,以下脚本可用于解析四个记录:

use warnings;
use strict;

my @records;

while (<DATA>) {
    if (/^NAME     (.{22})ADDRESS     (.*)/) {
        push @records, {
            name => $1,
            address => $2,
        };

    } elsif (/^\s{43}(.*)/) {
        $records[-1]{address} .= "\n$1";

    } else {
        warn "Unknown format on $.: $_";
    }
}

# Strip extra spacing from all fields
for (@records) {
    for (values %$_) {
        s/\s+$//mg;
    }
}

# Output records for debugging
use Data::Dump;
dd \@records;

__DATA__
NAME     Sprinkle, Jonathan U  ADDRESS     16887 36 St NW    
                                           Calgary, AB T8O 0B0
NAME     Nguyen, Michael S     ADDRESS     100A  
                                           8447 149 Ave NW    
                                           Sherwood Park, AB T6J    0Z0
NAME     Sprinkle, Jonathan U  ADDRESS     16887 36 St NW    
                                           Calgary, AB T8O 0B0
NAME     Nguyen, Michael S     ADDRESS     100A  
                                           8447 149 Ave NW    
                                           Sherwood Park, AB T6J    0Z0

输出:

[
  {
    address => "16887 36 St NW\nCalgary, AB T8O 0B0",
    name => "Sprinkle, Jonathan U",
  },
  {
    address => "100A\n8447 149 Ave NW\nSherwood Park, AB T6J    0Z0",
    name => "Nguyen, Michael S",
  },
  {
    address => "16887 36 St NW\nCalgary, AB T8O 0B0",
    name => "Sprinkle, Jonathan U",
  },
  {
    address => "100A\n8447 149 Ave NW\nSherwood Park, AB T6J    0Z0",
    name => "Nguyen, Michael S",
  },
]

答案 2 :(得分:0)

对于初学者,你的两个样本都没有显示多行。所以我马上就看不出如何根据你的例子来帮助你了。

大多数情况下,这将是默认输入记录分隔符的问题。这意味着Perl在处理文件时的默认行为是一次为您提供一行。除非你为此做些什么,否则你永远不会得到你想要的东西。

控制它的变量是$/,因此假设FILE是您的打开文件句柄,您需要执行以下操作:

local $/;
my $contents = <FILE>;

现在$contents将文件的全部内容包含为嵌入了所有"\n"的单个字符串。那么你实际上可以尝试你的比赛。