2011-05-11 41 views
2

我知道有一个库,做到这一点如何在perl中验证数字?

使用标量::的Util QW(looks_like_number);

但我想用perl正则表达式来做。而且我希望它能够用于双数而不仅仅是整数。

所以我想要的东西比这个

是$ var更好=〜/^[+ - ] \ d + $/

感谢?

+1

你知道,数字可以有一个可选部分(....)?组成部分后。至少,你已经尝试了一下。 – Ingo 2011-05-11 14:21:25

+0

我尝试了一个我放在我的问题上,它检查一个数字(3.5)作为例子时不起作用。 – 2011-05-11 14:29:34

+2

它是DID的工作 - 它告诉你正确,你的模式不匹配整个字符串“3.5” – Ingo 2011-05-11 14:32:09

回答

14

构造一个正则表达式来验证一个数字是非常困难的。只有太多标准需要考虑。 Perlfaq4包含了部分“如何确定一个标是否是数字/全/整数/浮动

从该文件中的代码显示了以下测试:?

if (/\D/)       {print "has nondigits\n"  } 
if (/^\d+$/)      {print "is a whole number\n" } 
if (/^-?\d+$/)      {print "is an integer\n"  } 
if (/^[+-]?\d+$/)     {print "is a +/- integer\n" } 
if (/^-?\d+\.?\d*$/)    {print "is a real number\n" } 
if (/^-?(?:\d+(?:\.\d*)?|\.\d+)$/) {print "is a decimal number\n"} 
if (/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) { 
    print "is a C float\n" 
} 
  • 第一个测试不够格的无符号整数
  • 第二个测试是否符合整数
  • 第三个测试是否符合整数。
  • 第四个测试符合正/负符号整数。
  • 第五个测试符合实数。
  • 第六个测试符合十进制数。
  • 第七个测试以c式科学记数法定义数字。

所以,如果您使用的是这些测试(不包括第一个测试),您将不得不验证一个或多个测试通过。然后你有一个号码。

另一种方法,因为您不想使用模块Scalar :: Util,您可以从代码IN Scalar :: Util中学习。 looks_like_number()函数如下设置:

sub looks_like_number { 
    local $_ = shift; 

    # checks from perlfaq4 
    return $] < 5.009002 unless defined; 
    return 1 if (/^[+-]?\d+$/); # is a +/- integer 
    return 1 if (/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/); # a C float 
    return 1 if ($] >= 5.008 and /^(Inf(inity)?|NaN)$/i) 
      or ($] >= 5.006001 and /^Inf$/i); 

    0; 
} 

您应该能够使用适用于您的情况的那部分功能。

但是我想指出的是,Scalar::Util是一个核心的Perl模块;它附带Perl,就像strict一样。所有的最佳实践可能只是使用它。

+0

您输入的函数在输入中不同于输入'looks_like_number('0'但'true')'! – ikegami 2011-05-11 19:29:34

+0

...和超载对象。重载的对象在最新版本的Scalar :: Util :: PP中处理。 PP版本不再存在于发行版的最新发行版中。 – ikegami 2011-05-11 19:35:21

+0

是的,Scalar-List-Utils-1.23有一个纯Perl版本,而Scalar-List-Utils-1.23_03没有。读者可以轻松地在CPAN上查找v1.23的源代码,因为该版本处理重载的对象。然而,我完全相信这个对话重申了这样的观点:当Scalar :: Util的looks_like_number()已经存在时,尝试用正则表达式构建一个新的通用数字合格解决方案是愚蠢的;几乎肯定会变得更加健壮,更现代化,更易于维护。另外,它是标准Perl发行版的一部分。 – DavidO 2011-05-11 19:47:31

6

您应该使用Regexp :: Common,大多数模式比您意识到的要复杂得多。

use Regexp::Common; 

my $real = 3.14159; 
print "Real" if $real =~ /$RE{num}{real}/; 

然而图案默认情况下不固定,因此更严格的版本是:

my $real_pat = $RE{num}{real}; 
my $real  = 3.14159; 
print "Real" if $real =~ /^$real_pat$/; 
+0

不幸的是,Regexp :: Common传递了普通人可能认为有效的数字语法的东西,例如:'1..2','-1.0.2'和'1.-2'。另一个支持Scalar :: Util方法是最好的方法的例子。 – DavidO 2011-05-11 20:56:10

+0

@DavidO该文档指出该匹配未被锚定。那些模式如果锚定在那里,则不匹配实际的数字。如果没有锚定,它们会匹配。 – 2012-07-31 02:43:00

+0

也许这是合理的编辑您的帖子,以保持更强大的正则表达式:'m/^ $ RE {num} {real} $ /'。我还没有测试过是否会拒绝“'1.-2”“。顺便说一句:我做了++你的答案。 – DavidO 2012-07-31 02:47:00

0

那么首先你应该确保该号码不包含任何逗号所以你这样做:

$ var =〜s /,// g; #删除所有逗号

然后创建另一个变量来完成比较的其余部分。

$ var2 = $ var;

然后删除。从新变量中只有一次出现。

$ var2 =〜s /.//; #替换。没有什么比较,但只有一次。

现在var2应该看起来像一个没有“。”的整数。 这样做:

if($var2 !~ /^[+-]?\d+$/){ 
     print "not valid"; 
    }else{ 
     #use var1 
    } 

就可以解决这个问题的代码,如果你需要使用它不止一次把它写成一个函数。 干杯!