【问题标题】:Perl match only returning "1". Booleans? Why?Perl只匹配返回“1”。布尔值?为什么?
【发布时间】:2011-12-12 22:15:57
【问题描述】:

这一定很明显,但我只是没看到。

我有一个包含数千条记录的文档,如下所示:

Row:1 DATA:
[0]37755442
[1]DDG00000010
[2]FALLS
[3]IMAGE
[4]Defect
[5]3
[6]CLOSED

我已经设法将每条记录分开,现在我正在尝试解析每个字段。

我正在尝试匹配编号的标题,以便我可以提取成功的数据,但问题是我的匹配只在成功时返回“1”,如果不成功,则什么也没有。我尝试申请的任何比赛都会发生这种情况。

例如,应用于每条记录中的一个简单单词:

my($foo) = $record=~ /Defect/;
print STDOUT $foo;

如果每条记录包含“缺陷”,则打印出“1”,如果包含其他内容,则不打印。

或者:

$record =~ /Defect/;
print STDOUT $1;

什么都不打印。

$record =~ s/Defect/Blefect/

另一方面,将“缺陷”替换为“瑕疵”非常好。

我真的很困惑,为什么我的比赛的回报如此糟糕。 任何帮助将不胜感激。

【问题讨论】:

  • 匹配后您希望在$foo 中出现什么?
  • 很多人已经给了你正则表达式问题的答案,但我认为你问的是一个 XY 问题。 I'm trying to match the numbered headers so that I can pull out the data that succeeds them: 你希望你最终的数据结构是什么样的?很可能它可以比循环和正则表达式更快地完成。

标签: regex perl parsing


【解决方案1】:

来自perlop, Quote and Quote-Like operators [括号中的位由我添加]:

/PATTERN/msixpodualgc

在字符串中搜索模式匹配,在标量上下文中如果成功则返回 true [1],如果失败则返回 false [undef]。

(查看s/// 上的部分也会很有用;-)

Perl 只是没有谨慎的布尔类型或true/false 别名,所以经常使用1undef:但是,它可以很好地可以是其他值,而不会使文档不正确。

$1 永远不会被定义,因为没有捕获组:也许需要$& (aka $MATCH)? (或者更好的是,将正则表达式更改为具有捕获组;-)

编码愉快。

【讨论】:

  • 您好,感谢您的回复。它不应该在列表上下文中返回匹配列表吗? @foo = ($bug =~ /Defect/);打印标准输出@foo;或打印 STDOUT @foo[0];会给我完全相同的东西。
  • @ManAnimal 添加捕获组并进行比较。 :)
【解决方案2】:
my($foo) = $record=~ /Defect/;
print STDOUT $foo;

你应该这样做而不是这样做

$record =~ /Defect/;
my $foo = $&; # Matched portion of the $record.

因为您的目标似乎是获得匹配的部分。 返回值是真/假,表示匹配是否成功。

你可能会发现http://perldoc.perl.org/perlreref.html很方便。

【讨论】:

    【解决方案3】:

    您需要使用捕获括号来实际捕获:

    if ($record =~ /(Defect)/ ) {
        print "$1\n";
    }
    

    【讨论】:

    • 太棒了。做到了。我翻遍了一遍又一遍,从来没有遇到过捕获括号。我一定是个盲人。非常感谢。
    【解决方案4】:

    =~ perl 运算符接受一个字符串(左操作数)和一个正则表达式(右操作数)并将字符串与 RE 匹配,根据 re 是否匹配返回一个布尔值(true 或 false)。

    现在 perl 并没有真正的布尔类型——相反,在布尔上下文中,每个值(任何类型)都被视为“真”或“假”——大多数事情都是“真”,但空字符串和未定义事物的特殊“undef”值是假的。因此,当返回一个布尔值时,它通常使用 '1' 表示 true,使用 ''(空字符串)表示 false。

    现在关于您的最后一个问题,尝试打印 $1 什么也打印不出来。每当你匹配一个正则表达式时,perl 将$1$2 ... 设置为带有正则的括号子表达式的值。但是,在您的示例中,没有带括号的子表达式,因此 $1 始终为空。如果你把它改成

    $record =~ /(Defect)/;
    print STDOUT $1;
    

    你会得到更符合你期望的东西(Defect,如果匹配,则什么都不匹配)。

    我通常看到的最常见的正则表达式匹配习惯是这样的:

    if ($string =~ /regexp with () subexpressions/) {
        ... code that uses $1 etc for the subexpressions matched
    } else {
        ... code for when the expression doesn't match at all
    }
    

    【讨论】:

      【解决方案5】:

      我认为您真正想要的是将正则表达式括在括号中:

      my($foo) = $record=~ /(Defect)/;
      

      在列表上下文中,返回的是组,而不是匹配项本身。而且您的原始代码没有组。

      【讨论】:

      • 这很有帮助 - 谢谢。我忘记了绑定运算符在标量/列表上下文中的不同行为。
      【解决方案6】:

      如果您希望匹配结果为“真”或“假”,则在标量上下文中进行模式匹配。这就是您在第一个示例中所做的。您执行了模式匹配并将结果分配给标量 my($foo)。所以 $foo 得到了一个“真”或“假”的值。

      但是,如果您想捕获与您的模式的一部分匹配的文本,请使用分组括号,然后检查相应的 $ 变量。例如,考虑以下表达式:

      $record =~ /(.*)ing/
      

      单词“speaking”的匹配会将“speak”分配给 $1,“listening”会将“listen”分配给 $1,等等。这就是您在第二个示例中尝试做的事情。问题是您需要添加分组括号。 "$record =~ /Defect/" 不会为 $1 分配任何内容,因为模式中没有分组括号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-11
        • 2020-01-17
        • 2020-03-21
        • 2017-11-07
        • 2017-01-25
        • 1970-01-01
        • 2014-03-20
        • 1970-01-01
        相关资源
        最近更新 更多