perl中的模式匹配

时间:2014-09-08 10:09:43

标签: regex perl

my $line = "Name:Amanda_Marry_Rose,Region:US,host:USE,cardType:DebitCard,product:Satin,Name:Raghav.S.Thomas,Region:UAE,";
my $name = "";

@name = ( $line =~ m/Name:([\w\s\_\,/g );
foreach (@name) {
   print $name."\n";
}

我希望在整个行中出现Name:,Region之间的单词。主要的漏洞是名称可以是任何格式

Amanda_Marry_Rose
Amanda.Marry.Rose
Amanda Marry Rose
Amanda/Marry/Rose

每次在线上发生这种模式时,我需要帮助。所以对于我提供的行,输出应该是

Amanda_Marry_Rose
Raghav.S.Thomas

有谁知道如何做到这一点?我试着保留下面的行,但它给了我错误的输出。

@name=($line=~m/Name:([\w\s\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~\´]+)\,/g);

输出

Amanda_Marry_Rose,Region:US,host:USE,cardType:DebitCard,product:Satin,Name:Raghav.S.Thomas,Region:UAE

4 个答案:

答案 0 :(得分:3)

要在Name:和第一个逗号之间进行捕捉,请使用negated character class

/Name:([^,]+)/g

这表示匹配Name:之后的一个或多个不是逗号的字符:

while (/Name:([^,]+)/g) {
    print $1, "\n";
}

这比非贪婪的quantifier更有效,例如:

/Name:(.+?),/g

因为它不需要backtracking

答案 1 :(得分:0)

Reg-ex更正:

my $line = "Name:Amanda_Marry_Rose,Region:US,host:USE,cardType:DebitCard,product:Satin,Name:Raghav.S.Thomas,Region:UAE,";

my @name = ($line =~ /Name\:([\w\s_.\/]+)\,/g);
    foreach my $name (@name) {
    print $name."\n";
}

答案 2 :(得分:0)

你所拥有的是以逗号分隔的数据。你应该如何解析这取决于你的数据。如果它是完整的csv数据,最安全的方法是使用适当的csv解析器,例如Text::CSV。如果它不是那么严格的数据,你可以使用轻量级解析器Text::ParseWords,它也可以作为Perl 5中的核心模块。如果你在这里有相当基本的,用户输入的字段,然后我会推荐split - 只是因为当你知道分隔符时,定义它的内容比其他内容更容易,更安全。

use strict;
use warnings;
use Data::Dumper;

my $line = "Name:Amanda_Marry_Rose,Region:US,host:USE,cardType:DebitCard,product:Satin,Name:Raghav.S.Thomas,Region:UAE,";

# Simple split
my @fields = split /,/, $line;
print Dumper for map /^Name:(.*)/, @fields;

use Text::ParseWords;
print Dumper map /^Name:(.*)/, quotewords(',', 0, $line);

use Text::CSV;
my $csv = Text::CSV->new({
        binary => 1,
    });
$csv->parse($line);
print Dumper map /^Name:(.*)/, $csv->fields;

这些选项中的每一个都提供相同的输出,除了使用Text::CSV的选项之外,还会非常正确地发出未定义的警告,因为您的数据有一个尾随逗号(意味着末尾是空字段)

每一种都有不同的优点和缺点。 Text::CSV可能会阻止不符合CSV格式的数据,split无法处理嵌入式逗号,例如Name:"Doe, John",...

我们用来非常简单地提取名称的正则表达式只捕获以Name:开头的所有其余行。这也允许您对字段名称执行完整性检查,例如,如果您突然发现名为Doe;Name:的字段

,则发出警告

答案 3 :(得分:0)

简单的方法是在字符串中Name:的每个实例后查找所有非逗号字符序列。

use strict;
use warnings;

my $line = 'Name:Amanda_Marry_Rose,Region:US,host:USE,cardType:DebitCard,product:Satin,Name:Raghav.S.Thomas,Region:UAE,';

my @names = $line =~ /Name:([^,]+)/g;

print "$_\n" for @names;

<强>输出

Amanda_Marry_Rose
Raghav.S.Thomas

但是,将数据解析为哈希数组以便将相关字段收集在一起可能很有用。

use strict;
use warnings;

my $line = 'Name:Amanda_Marry_Rose,Region:US,host:USE,cardType:DebitCard,product:Satin,Name:Raghav.S.Thomas,Region:UAE,';

my %info;
my @persons;
while ( $line =~ / ([a-z]+) : ([^:,]+) /gix ) {

   my ($key, $val) = (lc $1, $2);

   if ($info{$key}) {
     push @persons, { %info };
     %info = ();
   }

   $info{$key} = $val;
}
push @persons, { %info };

use Data::Dump;
dd \@persons;

print "\nNames:\n";
print "$_\n" for map $_->{name}, @persons;

<强>输出

[
  {
    cardtype => "DebitCard",
    host     => "USE",
    name     => "Amanda_Marry_Rose",
    product  => "Satin",
    region   => "US",
  },
  {
    name   => "Raghav.S.Thomas",
    region => "UAE",
  },
]

Names:
Amanda_Marry_Rose
Raghav.S.Thomas