Perl使用if语句验证输入的函数

时间:2014-06-16 16:54:04

标签: perl function validation if-statement

我想创建一个Perl函数,如下所示:

$iError = _validate( "$cVariable", "c" );

$cVariable - 我要根据预定义的标准

进行验证的输入
"c" – the type of data that is expected
    c = character
    a = alphanumeric
    i = integer
    x = decimal number
    d = date, two default formats are YY_MM_DD and YYYY_MM_DD
    f = file/dir name
    e = characters that are valid in an email address (email address must have \@ instead of just @)

返回值:

Success = 0 
Failed = -1

这是我到目前为止所得到的,但肯定有一些格式错误,我无法捕捉,因为我对Perl完全不熟悉,有人能指出我哪里出错吗?

$iError=_validate($cVariable, c)

if ($c == c) {
    if ($cVariable =~ ^.+$) {
        $iError=0
    } else {
            $iError=-1 
    } # end if

elsif  ($c == a) {
    if ($cVariable =~ ^([a-z])|([0-9])+$) {
    %iError=0
    } 
    else {$iError=-1} # end if
    } 

elsif ($c == i) {
    if ($cVariable =~ ^[-+]?\d+$) {
    $iError=0
    } 
    else {$iError = -1} # end if
    } 

elsif ($c == x) {
    if ($cVariable =~ ^[0-9]+[.][0-9]+$) {
    $iError=0
    } 
    else {$iError=-1} # end if
    } 

elsif ($c == d) {
    if ($cVariable =~ ^\d{2}_{1}\d{2}_{1}\d{2}$) {
    $iError=0
    }
    elsif ($cVariable =~ ^\d{4}_{1}\d{2}_{1}\d{2}$) {
    $iError=0
    }
    else {$iError=-1} # end if
    } 

elsif($c == f) {
    if ($cVariable =~ ^.+$) {
    $iError=0
    }
    else {$iError=-1} # end if
    } 

else($c == e) {
    if ($cVariable =~ ^\S{0,50}\\@\S{0,20}[.]\S{1,10}$) {
    $iError=0
    }
    else {$iError=0} # end if
    } # end outer if

return($iError);

3 个答案:

答案 0 :(得分:1)

在学习Perl的同时开发解决方案的一种方法是采用Test Driven Development [TDD]方法,在该方法中,您开始编写一个或多个测试,然后开发代码以使测试通过

对于您所述的问题,您可以从测试文件开始(将其称为' validate.t'并将其放在名为' t'的目录中):

#!/usr/bin/env perl -I.
use Test::More ;
BEGIN { require_ok( "ValidateStarter.pl" ) ; }

my $cVariable = 'abc' ;
my $iError = validate( $cVariable, 'c' ) ;
is( $iError, 0, "correctly validated a character string ($cVariable)" ) ;

$cVariable = 'def456' ;
$iError = validate( $cVariable, 'c' ) ;
is( $iError, -1, "correctly validated a non-character string ($cVariable)" ) ;

$cVariable = 'def456' ;
$iError = validate( $cVariable, 'a' ) ;
is( $iError, 0, "correctly validated an alphanumeric string ($cVariable)" ) ;

$cVariable = '123' ;
$iError = validate( $cVariable, 'a' ) ;
is( $iError, -1, "correctly validated a non-alphanumeric string ($cVariable)" ) ;

$cVariable = '1' ;
$iError = validate( $cVariable, 'i' ) ;    
is( $iError, 0, "correctly validated an integer ($cVariable)" ) ;

$cVariable = 'z' ;
$iError = validate( $cVariable, 'i' ) ;
is( $iError, -1, "correctly validated a non-integer ($cVariable)" ) ;

$cVariable = '123.456' ;
$iError = validate( $cVariable, 'x' ) ;
is( $iError, 0, "correctly validated a decimal number ($cVariable)" ) ;

$cVariable = '-0.1234567' ;
$iError = validate( $cVariable, 'x' ) ;
is( $iError, 0, "correctly validated a decimal number ($cVariable)" ) ;

$cVariable = '1234567' ;
$iError = validate( $cVariable, 'x' ) ;
is( $iError, 0, "correctly validated a decimal number ($cVariable)" ) ;

$cVariable = '0xDEADBEEF' ;
$iError = validate( $cVariable, 'x' ) ;
is( $iError, -1, "correctly validated a non-decimal number ($cVariable)" ) ;

done_testing ;

接下来,在上面的目录' t /,创建一个名为ValidateStarter.pl的文件:

#!/usr/bin/env perl
use strict ;
use warnings ;
use Regexp::Common qw( number ) ;
sub validate {    
    my ( $cVar, $c ) = @_ ;    
    if ( 'c' eq $c ) {
        if ( $cVar =~ /^[[:alpha:]]+$/ ) {
            return 0 ;
        }    
    }
    elsif ( 'a' eq $c ) {
        if ( $cVar =~ /^[[:alpha:]][[:alnum:]]+$/ ) {
            return 0 ;
        }
    }
    elsif ( 'i' eq $c ) {
        if ( $cVar =~ /^$RE{num}{int}$/ ) {
            return 0 ;
        }
    }
    elsif ( 'x' eq $c ) {
        if ( $cVar =~ /^$RE{num}{decimal}$/ ) {
            return 0 ;
        }
    }
    elsif ( 'a' eq $c ) {
        if ( $cVar =~ /^\A\p{Alnum}+\z$/ ) {
            return 0 ;
        }
    }    
    return -1 ;   
}
1 ;

通过更改到包含ValidateStarter.pl和t /目录的目录并键入来执行测试(注意:' $'将是您的控制台提示符 - 不要键入它):

$ perl t/validate.t

如果你能弄明白如何制作' validate.t'一个可执行文件(提示:在Linux上使用' chmod'),然后你可以输入:

$ t/validate.t

在Linux上,你会看到:

$ t/validate.t
ok 1 - require 'ValidateStarter.pl';
ok 2 - correctly validated a character string (abc)
ok 3 - correctly validated a non-character string (def456)
ok 4 - correctly validated an alphanumeric string (def456)
ok 5 - correctly validated a non-alphanumeric string (123)
ok 6 - correctly validated an integer (1)
ok 7 - correctly validated a non-integer (z)
ok 8 - correctly validated a decimal number (123.456)
ok 9 - correctly validated a decimal number (-0.1234567)
ok 10 - correctly validated a decimal number (1234567)
ok 11 - correctly validated a non-decimal number (0xDEADBEEF)
1..11

' OK'在一行输出上意味着测试通过了,而“不好”'意味着它失败了。

从这些工作代码行开始,我建议采取进一步的步骤:

  1. 有关如何在Perl中编写测试的更多信息,请阅读Test::Tutorial
  2. 阅读Regexp::Common::number,了解如何使用一些优秀的正则表达式实用程序。
  3. Browse the online text of 'Modern Perl'通过chromatic阅读更多关于Perl本身的信息。
  4. 研究并修改示例代码,直到您了解它是如何工作的。
  5. 添加更多适用于示例代码的测试用例。
  6. 添加适用于问题规范中其他订单项的测试用例。并跟进代码以使测试通过。
  7. 调试&添加更多测试用例,直到您完成。
  8. 根据您问题的具体性质来判断,它似乎可能基于具有特定截止日期的作业,因此您可能认为自己没有时间编写自动化测试;但是,当您了解开发解决方案时需要了解的内容时,TDD是逐步取得进展的好方法。

    请记住,您将知道您在截止日期前完成的任何部分都可以通过您所撰写的测试证明。

答案 1 :(得分:0)

当您执行RegEx(" =〜")时,您需要用" /"包围表达式。因此,您的第一个RegEx if语句应如下所示:

if ($cVariable =~ /^.+$/) {

答案 2 :(得分:0)

你的代码已经破碎且不够完整,以至于我不愿意浏览所有错误信息只是为了让它编译,因为你最终仍然会有一个有缺陷的解决方案。

语法,几乎任何人都可以学习。但更重要的问题是,您尝试验证的每件事(除了角色)都不像您期望的那样微不足道。鉴于验证电子邮件地址或日期所涉及的复杂性,可靠的CPAN模块提供的经过充分验证的代码是可行的方法。例如,你真的不想浪费大量时间来充实日期验证器的细节。

以下是我如何开始使用它。以下代码提供了您所描述的行为(文件/目录除外,因为我不知道您想要什么)。但它以一种可能比单独的正则表达式匹配更正确的方式实现:

#!/usr/bin/env perl

use strict;
use warnings;

use Scalar::Util 'looks_like_number';
use Date::Calc   'check_date';
use Email::Valid;

use constant VALIDATORS => {
  'c' => \&char,    # Validate a single character.
  'a' => \&alnum,   # Validate string is alphanumeric only.
  'i' => \&intgr,   # Validate input is an integer.
  'x' => \&dec,     # Validate input is a number.
  'd' => \&date,    # Validate input is a date in YYYY_MM_DD or YY_MM_DD
  'f' => \&fdn,     # Who knows?!  Something to do with file validation.
  'e' => \&eml,     # Validate input is a legal email address.
};

sub validate {
  my( $input, $mode ) = @_;
  die "No mode provided." unless defined $mode;
  die "Invalid mode: $mode." unless exists VALIDATORS->{$mode};
  return -1 if not defined $input;
  return VALIDATORS->{$mode}->($input) ? 0 : -1;
}

sub char {
  my $c = shift;
  return 1 == length $c;
}

sub alnum {
  my $an = shift;
  return $an =~ /\A\p{Alnum}+\z/;
}

sub intgr {
  my $n = shift;
  return looks_like_number($n) && $n == int($n);
}

sub dec {
  return looks_like_number(shift);
}

sub date {
  my $date = shift;
  my( $y, $m, $d );
  if( ( $y, $m, $d ) = $date =~ m/\A(\d{2}|\d{4})_(\d{2})_(\d{2})\z/ ) {
    return check_date( $y, $m, $d );
  }
  else {
    return 0;
  }
}

sub fdn {
  # I have no idea what you want to do in validating a filename or directory.
  # Is this a matter of "legal characters" for a given OS?
  # Or is it a matter of "This file / path exists"?
}

sub eml { return Email::Valid->address(shift) }

# ___________________________

use Test::More;

{
  local $@;
  eval{ validate('a') };
  like ( $@, qr/^No mode provided/, 'Die if no mode provided.' );
}

{
  local $@;
  eval{ validate('a','invalid') };
  like( $@, qr/^Invalid mode/, 'Die on invalid mode.' );
}

# 0 = success, -1 = failure.
ok( 0  == validate( 'a','c' ), 'Char accepted.' );
ok( -1 == validate( 'ab', 'c' ), 'More than one char rejected.' );
ok( -1 == validate( '', 'c' ), 'Empty string rejected.' );
ok( -1 == validate( undef, 'c' ), 'undefined value rejected.' );

# 0 = success, non-zero = failure (-1).
ok( !validate( 'aA10', 'a' ), 'Alnum accepted.' );
ok( validate( '.$', 'a' ), 'Non-alnum rejected.' );
ok( validate( undef,'a' ), 'undefined value rejected for alnum.' );

ok( !validate( '10', 'i' ), 'Positive integer.' );
ok( !validate( -5, 'i' ), 'Negative integer.' );
ok( validate( -0.5, 'i' ), 'Reject non-integer.' );
ok( validate( 'a', 'i' ), 'Reject non-numeric as int.' );

ok( !validate( '10', 'x' ), 'Positive integer as decimal number.' );
ok( !validate( '10.5', 'x' ), 'Positive floating point as decimal number.' );
ok( validate( '17f', 'x' ), 'Decimal rejects hex string.' );
ok( validate( '12.3.5', 'x' ), 'Malformed decimal rejected.' );

ok( !validate( '1600_12_15', 'd' ), 'Four digit year date accepted.' );
ok( !validate( '14_06_05', 'd' ), 'Two digit year date accepted.' );
ok( validate( '15000_12_15', 'd' ), 'Y10k bug ;)' );
ok( validate( '2000_02_30', 'd' ), 'Impossible date rejected.' );

ok( !validate( 'someone@example.com', 'e' ), 'Good email address accepted.' );
ok( validate( 'a"b(c)d,e:f;g<h>i[j\k]l@example.com', 'e' ),
               'Bad email rejected.' );
ok( validate( 'a@b@example.com', 'e' ), 'Bad email rejected.' );


done_testing();

我并不特别关心“0 ==成功,-1 ==失败”模式,但这并非闻所未闻,而且很容易实现。

CPAN上有一些模块可能会更好地验证整数和数字,欢迎您搜索它们并将它们放到适当的位置。我对这些类别的测试既快又脏,在大多数情况下都应该有效。

有关数字验证的更多详细信息,请查看perlfaq4

我没有尝试验证文件名或目录,因为我不确定你在这方面的目的是什么。 File :: Util模块可用于验证文件名对于给定的操作系统是否合法。至于路径,我不确定你是否想知道字符是否合法,或者路径是否存在。你必须自己解决这个问题。

当最后期限临近时,这一切都不是Perl的新手应该对自己采取的那种事情。在脸上看起来非常简单的东西中有很多学习。