Perl使用正则表达式来比较具有多个分隔符的字段

时间:2017-03-08 03:19:49

标签: perl

我在学习Perl。 我的data.txt文件包含:

Lori:James Apple
Jamie:Eric Orange

下面的代码打印第一行" Lori:James Apple"

open(FILE,'data.txt');
while(<FILE>){
  print if /James/;
}

但是如何修改我的正则表达式以搜索特定字段? 例如,我想使用2个分隔符&#39; &#39;和&#39;:&#39;使每行包含3个字段并检查第一行的第3个字段是否为Apple。这相当于awk -F'[ :]' '$3 = "Lori"' data.txt

2 个答案:

答案 0 :(得分:4)

正则表达式的一个简单方法是使用negated character class(另见in perlreftut

open my $fh, '<', $file  or die "Can't open $file: $!";

while (my $line = <$fh>) 
{
    my @fields = $line =~ /([^:\s]+)/g;
}

[^...]匹配除里面列出的字符之外的任何字符(在^之后&#34;否定&#34;)。 + quantifier表示匹配一次或多次,因此整个模式匹配除:和&#34;空格之外的连续字符串。&#34;有关\s的准确说明,请参阅文档。如果您实际上只想跳过单个文字空间,请使用[^: ]。所有这些都由() 捕获

由于全局修饰符 /g,搜索会继续浏览字符串,找到所有此类匹配项。由于它位于列表context 中,因此返回匹配列表,该列表已分配给@fields数组。

人们可以随时随地挑选元素&#34;通过索引到列表($line =~ /([^:\s]+)/g)[2]。如果我们匹配$_,则为(/([^:\s]+)/g)[2]

对于初学者,我建议您仔细阅读perlreftut

另一方面,使用split

通常更简单,更清晰
my @fields = split /[:\s]/, $line;

这也使用正则表达式来分割字符串的模式。字符类不会被否定,因为它在这里指定了分隔符本身,:\s(每个分隔符可以是其中之一,它们不必都是相同的)。< / p>

我现在想回答具体问题,但问题并不清楚。

它要求&#34; 检查第一行的第3个字段是否为Apple &#34;,例如可以做什么

while (<$fh>) 
{
    if ( (/([^:\s]+)/g)[2] eq 'Apple' ) {
        # ....
    }
}

但它并不清楚如何处理它。或许通过第三个领域获得第一个领域?

我建议获取一个数组,然后进行处理。可以编写一个正则表达式来直接识别和选择字段,但这更加脆弱,正则表达式本身则取决于字段的位置(和数量)。

此时我们正处于猜谜游戏中。如果您需要更多细节,请澄清。

给定的awk代码会产生Lori James Lori,但我不知道这是怎么回事。

答案 1 :(得分:0)

简短的回答是 - 不要。正则表达式是关于模式匹配,而不是上下文。

可以定义一个以分隔符和字段构建的模式,但是......它不适合这项工作。

答案是使用split然后单独处理字段。

open ( my $input, '<', 'data.txt' ) or die $!; 
while(<$input>){
    chomp;
    my @fields = split /[\s:]/;
    print if $fields[2] eq "Apple";
}

如果您愿意,可以进一步压缩,但我建议谨慎 - 以可读性为代价来压缩代码并不是一种美德。

另外 - 当我们在这里时:

open(FILE,'data.txt');

是错误的样式 - 它不会检查是否成功,它还使用全局文件句柄名称。它会好得多:

open ( my $input, '<', 'data.txt' ) or die $!;

autodie编译指示也隐式执行此操作。