1

我在另一个主题中询问了有关匹配数字(例如 123)的问题。这太狭窄了,随着我对 Regex 的深入了解,我发现您确实必须定义任何东西。所以我要求指数符号并在这篇文章中得到答案:/^keyword\s+(-?(?:\d+|\d*\.\d*)(?:[Ee]-?(?:\d+|\d*\.\d*))?)/。我试图理解这一点,但到目前为止失败了。

所以我现在问的更具体。我需要匹配数字,我在这里举一些例子:

13
-999
83.12300
.151
-.213
1e14
124e2
-9e-4

你明白了,普通的数学东西。

更具体地说,我给你我的 Perl 代码。我正在搜索keyword一条线上,需要从这条线上获取一个值。我想在一个正则表达式中获得这个值,因为我使用 or 语句的解决方法||似乎会导致问题。

my $value;
open(FILE,"data.dat") or die "error on opening data: $!\n";
while (my $line = <FILE>) {
        if (($line =~ /^keyword\s+(-?(?:\d+|\d*\.\d*)(?:[Ee]-?(?:\d+|\d*\.\d*))?)/x) || ($line =~ /^keyword\s*(\d*\.\d*)/)) {
                $value = $1;
        };
}
close(FILE);

编辑

感谢所有到目前为止的提示。

4

4 回答 4

2

转到 cpan 并获取Regexp::Common.

像这样使用它

use Regexp::Common;

my $re = $RE{num}{real};

if ( $line =~ /^keyword\s+($re)/ ) {
  $value = $1;
}

比自己动手的正则表达式滚动要容易得多。

于 2013-07-31T11:35:12.877 回答
1

您代码中的第二个正则表达式似乎是多余的,您可以安全地删除它。第一个正则表达式应该匹配你所有的测试用例。有什么它似乎无法使用的东西吗?

您还应该调整您的正则表达式,因为目前它认为-.e-.是一个数字。这来自拥有\d*\.\d*which matches .。您可以尝试(?:\d+(?:\.\d*)?|\.\d+)而不是您所拥有的,这将匹配 1) 数字,2) 数字后跟小数,可能还有更多数字,或 3) 小数后跟数字。

于 2013-07-31T11:34:52.020 回答
1

还有另一种方法可以做到这一点,您不需要正则表达式。您可以使用looks_like_numberScalar ::Util

下面是一个例子:在 Perl 中如何判断一个变量是否有数值?我把它贴在这里给你。


例子:

#!/usr/local/bin/perl

use warnings;
use strict;

use Scalar::Util qw(looks_like_number);

my @exprs = qw(1 5.25 0.001 1.3e8 foo bar 1dd);

foreach my $expr (@exprs) {
    print "$expr is", looks_like_number($expr) ? '' : ' not', " a number\n";
}

给出这个输出:

1 is a number
5.25 is a number
0.001 is a number
1.3e8 is a number
foo is not a number
bar is not a number
1dd is not a number

编辑:@borodin 的评论

你会以这样的方式使用它:

my $value;
open(FILE,"data.dat") or die "error on opening data: $!\n";
while (my $line = <FILE>) {
        if (($line =~ /^keyword +(.*)/)) {
             my $number = $1;
             if ( looks_like_number($number) ) { 
                 $value = $number;
             }
        };
}

编辑:如果你必须有一个正则表达式,你可以这样的表达式:

 #!/bin/perl
 use strict;
 use warnings;

 my @numbers = ( 'keyword 13',
                 ' word   25',
                 'keyword -999',
                 'keyword 83.12300',
                 'keyword  .151',
                 'keyword -.213',
                 'keyword 1e14',
                 'keyword 124e2',
                 'keyword -9e-4 ',
                 ' keyword  e43e',
                 'keyword 4.5.6',
                 'keyword 4..e',
                 'keyword NaN',
                 'keyword Inf');

 for (@numbers) {

      if ( /^keyword +(-?((\d+\.?\d*)|(\d*\.?\d+))([Ee]-?\d+)?)/ ) {

         print "$1 is a number\n";

     } else {
         print "$_ does not match keyword or is not a number\n";
     }

 }
于 2013-07-31T11:57:59.957 回答
0

感谢您提供的信息性帖子和我最近几天阅读的内容,我能够了解更多的正则表达式结构。所以对于这个相当简单的任务,我不想使用额外的模块/包,而是想坚持使用正则表达式。我进行了一些测试和更改,以消除冗余并适应我的任务。所以我不会在一行上有几个数字,并且一行可以有空格。此外,数字的结尾由分号定义。总而言之,我发布了我的最终代码。谢谢大家的帮助。

#!/usr/bin/perl

use strict;
use warnings;

my @numbers=(
"keyword 152;",
"keyword 12.23;",
"keyword -2.001;",
"keyword .123;",
"keyword -12.;",
"keyword 55.44.33;",
"keyword 3e14;",
"keyword -3.000e0014;",
"keyword 5e-04;",
"   keyword     5e-04;  ",
"keyword 5e-04  ;",
"keyword .1e2;",
"keyword 9.e3;",
"keyword -0.01E-03;",
"keyword 1.3e-03;",
"keyword 1dd;",
"keyword -12E3e1;",
"keyword -.e.;",
"keyword -.e-.;");

for (@numbers) {

if (    /\s* keyword \s+        # stuff before matched number
    ( -?            # optional minus sign
      (?:           # no saving of group in brackets
        (?:\d+\.?\d*)       # match trailing digit and possible floating point number
        |           # or
        (?:\.\d+)       # no trailing digit and forced fpn
      )
    (?:[Ee]-?\d+)?      # optional exponential notation
    )           # end of group to be matched
    ;\s*            # stuff after matched number
    /x) {

print "<<__$_\__>>\n\t $1 \n";
} else { 
print "<<__$_\__>>\n\t !!!!! no matching here !!!!!\n";
}
}

输出:

<<__keyword 152;__>>
     152 
<<__keyword 12.23;__>>
     12.23 
<<__keyword -2.001;__>>
     -2.001 
<<__keyword .123;__>>
     .123 
<<__keyword -12.;__>>
     -12. 
<<__keyword 55.44.33;__>>
     !!!!! no matching here !!!!!
<<__keyword 3e14;__>>
     3e14 
<<__keyword -3.000e0014;__>>
     -3.000e0014 
<<__keyword 5e-04;__>>
     5e-04 
<<__    keyword     5e-04;  __>>
     5e-04 
<<__keyword 5e-04   ;__>>
     !!!!! no matching here !!!!!
<<__keyword .1e2;__>>
     .1e2 
<<__keyword 9.e3;__>>
     9.e3 
<<__keyword -0.01E-03;__>>
     -0.01E-03 
<<__keyword 1.3e-03;__>>
     1.3e-03 
<<__keyword 1dd;__>>
     !!!!! no matching here !!!!!
<<__keyword -12E3e1;__>>
     !!!!! no matching here !!!!!
<<__keyword -.e.;__>>
     !!!!! no matching here !!!!!
<<__keyword -.e-.;__>>
     !!!!! no matching here !!!!!

PS:我读过?:代码运行时可能不会保存资源,这使得正则表达式不太友好,所以可能会忽略这一点。

于 2013-08-08T07:05:14.643 回答