【问题标题】:Perl regex digitPerl 正则表达式数字
【发布时间】:2012-01-02 02:37:03
【问题描述】:

在此代码部分考虑我的正则表达式:

use strict;

my @list = ("1", "2", "123");

&chk(@list);

sub chk {
    my @num = split (" ", "@_");
    foreach my $chk (@num) {
        chomp $chk;
        if ($chk =~ m/\d{1,2}?/) {
            print "$chk\n";
        }
    }
}

\d{4} 不会打印任何内容。 \d{3} 将仅打印 123。但是,如果我更改为\d{1,2}?,它将全部打印出来。我认为,根据我目前阅读的所有资料,{1,2} 的意思是:一位但不超过两位。所以它应该只打印1 和2,对吗?

我需要什么来提取包含仅一到两位数字的项目?

【问题讨论】:

    标签: regex perl digits


    【解决方案1】:

    \d{1,2} 如果在提供的字符串中的任意位置找到 1 或 2 位数字,则成功。额外的字符串内容不会导致匹配失败。如果您只想在字符串包含 1 位或 2 位数字时进行匹配,请执行以下操作:^\d{1,2}$

    【讨论】:

    • 不确定如何解释,但它按我的意愿工作。感谢大家的帮助。我还在学习。
    • ^ 表示字符串的开头,$ 表示字符串的结尾,因此 Elroy 的模式要求整个字符串为 1 位或 2 位数字。您的模式意味着字符串中任意位置的 1 或 2 位数字。
    • 所以它的意思是:匹配必须包含一位或两位数字,并且匹配的内容必须在开头和结尾。非常感谢。
    • 或者,使用前瞻和后瞻来确保紧跟在模式之后和之前的字符不是数字。此解决方案适用于您仍想在字符串中搜索数字但只搜索一位或两位数字的情况。
    • $ 并不意味着字符串的结尾。它允许一个可选的换行符(通常是数据输入的产物)。 \z 获取字符串的绝对结尾。
    【解决方案2】:

    您应该锚定正则表达式以获得所需的效果。内置函数grep 更适合这里,因为它是从要完成的数组中选择的:

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    my @list = ( 1, 2, 123 );
    print join "\n", grep /^\d{1,2}$/, @list;
    

    【讨论】:

      【解决方案3】:

      它似乎工作得很好!

      这里有一个提示:使用 Perl 变量 $`、$& 和 $'。这些变量是特殊的正则表达式变量,显示匹配前的字符串部分、匹配的内容和匹配后的字符串。

      这是一个示例程序:

      #! /usr/bin/env perl
      use strict;
      use warnings;
      use feature qw(say);
      use Scalar::Util;
      
      my @list = ("1", "2", "123");
      
      foreach my $string (@list) {
          if ($string =~ /\d{1,2}?/) {
              say qq(We have a match for "string"!);
              say qq("$`"  "$&"  "$'");
          }
          else {
              say "No match makes David Sad";
          }
      }
      

      输出将是:

      We have a match for "1"!
      ""  "1"  ""
      We have a match for "2"!
      ""  "2"  ""
      We have a match for "123"!
      ""  "1"  "23"
      

      它的作用是将字符串分成三部分:正则表达式匹配之前的字符串部分、正则表达式匹配的字符串部分和正则表达式匹配之后的字符串部分。

      在每种情况下,都没有 预匹配,因为正则表达式从字符串的开头匹配。我们还看到\d{1,2}? 在每种情况下都匹配一个数字,即使123 可能匹配两个数字。为什么?因为匹配说明符末尾的问号告诉正则表达式不要贪婪。在这种情况下,我们告诉正则表达式匹配一个或两个字符。好吧,它匹配一个。去掉问号,最后一行应该是这样的:

      We have a match for "123"!
      ""  "12"  "3"
      

      如果您想匹配一位或两位数,而不是三位或更多位,则必须指定一位或两位数之前和之后的字符串部分。像这样的:

      /\D\d{1,2}\D/
      

      这将匹配您的字符串foo12bar,但不匹配foo123bar。但是如果字符串是12 呢?在这种情况下,我们想说要么我们有字符串的开头,要么在我们的一个或两个字符匹配之前有一个非数字,我们要么在我们的结尾有一个非数字或字符串的结尾一两个字符匹配:

      /(\D|^)\d{1,2}(/D|$)/
      

      快速解释:

      • (\D|^):非数字或字符串的开头(^ 锚点)
      • d{1,2}:一位或两位数
      • (\D|$):非数字或字符串结尾($ 锚点)

      现在,它将匹配 12,但不匹配 123,它将匹配 foo12 和 foo12bar,但不匹配 foo123 或 foo123bar。

      只要寻找一位或两位数,我们可以简单地指定锚点:

      /^\d{1,2}$/;
      

      现在,它将匹配 1、12,但不匹配 foo12 或 123。

      主要是使用$`、$& 和$' 变量来帮助准确查看正则表达式匹配的内容以及匹配前后的内容。

      【讨论】:

      • 是的,我最初的工作很完美。不幸的是,它按照我的指示做,但不是我想要的,这是不同的。感谢您对正则表达式匹配的复杂性的全面解释。我需要的是找到可以应用我到目前为止所学知识的情况。重复。非常感谢。
      【解决方案4】:

      不,因为虽然正则表达式只匹配两位数字,但 $chk 仍然包含 123。如果您只想打印匹配的部分,请使用

      if ($chk =~ m/(\d{1,2})/) {
          print "$1\n";
      }
      

      注意括号和 $1。这会导致它只打印括号中的内容。

      另外,这段代码没有多大意义:

      sub chk {
          my @num = split (" ", "@_");
      

      因为@_ 已经是一个数组,所以把它变成一个字符串然后拆分它是没有意义的。只需这样做:

      sub chk {
          foreach my $chk (@_) {
      

      对于不是来自用户输入的数据,您也不需要使用chomp,因为它旨在删除尾随换行符。这些数据中没有换行符。

      【讨论】:

      • 啊...括号。 '$1​​' 是提取的项目所在的位置。但现在如果我更改为 '(\d{1,2})',它将打印 '1' '2' 和 '12'。如果我更改为“(\d{1,2}?)”,它将打印“1”“2”和“1”。但这越来越清楚了。谢谢。
      【解决方案5】:
      #!/usr/bin/perl
      use strict;
      
      my @list = ("1", "2", "123");
      
      &chk(\@list);
      
      sub chk {
      
          foreach my $chk (@{$_[0]}) {
              print "$chk\n" if $chk =~ m/^\d{1,2}$/ ;        
          }
      }
      

      【讨论】:

      • 这行得通,但它也有点超出我目前的 Perl 技能,所有这些引用都在进行中。很有启发性,我会花一些时间来研究这些差异。非常感谢。
      【解决方案6】:
      #!/usr/bin/perl
      use strict;
      use warnings;
      my @list = ("1", "2", "123");
      
      &chk(@list);
      
      sub chk {
          my @num = split (" ", "@_");
          foreach my $chk (@num) {
              chomp $chk;
              if ($chk =~ m/\d{1,2}/ && length($chk) <= 2) {
                  print "$chk\n";
              }
          }
      }
      

      【讨论】:

      • 解释一下。例如,想法/要点是什么?请通过editing (changing) your answer 回复,而不是在 cmets 中(without "Edit:"、"Update:" 或类似的 - 答案应该看起来像是今天写的)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多