我在另一个话题中询问了匹配123这样的数字。这太狭隘了,随着我对Regex的深入了解,我发现你真的需要定义任何东西。所以我要求指数表示法并在this post中得到答案:/^keyword\s+(-?(?:\d+|\d*\.\d*)(?:[Ee]-?(?:\d+|\d*\.\d*))?)/
。我试图理解这一点但到目前为止失败了。
所以我现在要求更具体。我需要匹配数字,我在这里给出一些例子:
13
-999
83.12300
.151
-.213
1e14
124e2
-9e-4
你得到了它,常规数学。
更具体地说,我为你提供了我的Perl代码。我在一行上搜索keyword
,需要从这一行获取一个值。我想在一个正则表达式中获得此值,因为我使用or-statement ||
的解决方法似乎会导致问题。
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);
修改
到目前为止所有提示都是如此。
答案 0 :(得分:2)
转到cpan并获取Regexp::Common
。
像这样使用
use Regexp::Common;
my $re = $RE{num}{real};
if ( $line =~ /^keyword\s+($re)/ ) {
$value = $1;
}
比自己动手正则表达式滚动容易得多。
答案 1 :(得分:1)
代码中的第二个正则表达式似乎是多余的,您可以安全地删除它。第一个正则表达式应匹配所有测试用例。有什么似乎没有合作吗?
您还应该调整正则表达式,因为它目前认为-.e-.
是一个数字。这来自\d*\.\d*
匹配.
。您可以尝试使用(?:\d+(?:\.\d*)?|\.\d+)
代替您拥有的内容,它可以匹配1)数字,2)数字后跟小数,可能更多数字,或3)小数后跟数字。
答案 2 :(得分:1)
还有另一种方法可以做到这一点,你不需要正则表达式。您可以使用Scalar::Util
中的looks_like_number
以下是一个例子:How do I tell if a variable has a numeric value in 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";
}
}
答案 3 :(得分: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:我已经读过?:
在代码运行时可能无法保存资源,这使得正则表达式对眼睛不太友好,所以可能会将其排除在外。