正则表达式可以在python模拟器中工作,但不能在perl中工作

2024-10-01 22:27:51 发布

您现在位置:Python中文网/ 问答频道 /正文

您好,我正在使用一个在线正则表达式模拟器来测试我所写的内容是否正确: 我想从以下文本中提取信息:

Test23242asdsa 800,03 23.05.19 22.05.19
Tdsadas,tsadsa test 1.020,03 23.05.19 22.05.19
Test,23242 0,03 23.05.19 22.05.19

我尝试在perl中使用相同的代码:

use strict;
my $entry = 'Test23242asdsa 0,03 23.05.19 22.05.19';
my ($name, $expense, $date_expense, $date_paid) = $1, $2, $3, $4 if ($entry =~ m/^(.+)\s((?:\d+\.)?\d{1,3},\d{2})\s(\d{2}\.\d{2}\.\d{2})\s(\d{2}\.\d{2}\.\d{2})$/);
print "Name: '$name', Expense: '$expense', Date: '$date_expense', Date Paid: '$date_paid' \n";

如果我在这里使用相同的正则表达式:

https://regex101.com/
^(.+)\s((?:\d+\.)?\d{1,3},\d{2})\s(\d{2}\.\d{2}\.\d{2})\s(\d{2}\.\d{2}\.\d{2})$

它可以正确地检测de regex。我认为python和perl使用了相同的正则表达式语法,所以我不知道发生了什么


Tags: name文本信息内容datemy模拟器perl
3条回答

虽然与赋值问题中的优先级没有直接关系,但值得注意的是:

my $x if 0

在假条件中称为my(),并且 是prohibited as of Perl 5.30.0

因此,一般来说,您应该避免执行这种“条件声明”:

my ($foo, $baz) = ($1, $2) if $entry =~ m/^(\w+) bar (\w+)$/

因为当条件(本例中的regexp匹配)为false时,可能会导致错误

对于特定的情况,最好依赖brian d foy的建议,并将结果直接分配给要填充的变量列表。然后可以在布尔上下文中使用赋值结果,如以下示例所示:

if (my ($foo, $baz) = $entry =~ m/^(\w+) bar (\w+)$/) {
   # use $foo and $baz for fun and profit...
}

或者,如果您在线路上循环:

while (defined(my $entry = <$fh>)) {
   my ($foo, $baz) = $entry =~ m/^(\w+) bar (\w+)$/
      or next;  # <-- executed only when the regexp match fails

   # use $foo and $baz for fun and profit...
}

regexp很好,问题在于如何设置变量

由于Perl的运算符优先级,您需要将$1, $2, $3, $4括在括号中才能进行列表赋值

换成

my ($name, $expense, $date_expense, $date_paid) = ($1, $2, $3, $4) if ($entry =~ m/^(.+)\s((?:\d+\.)?\d{1,3},\d{2})\s(\d{2}\.\d{2}\.\d{2})\s(\d{2}\.\d{2}\.\d{2})$/);

working demo

尽管它可能不适合您的任务,但Perl的match操作符在列表上下文中返回捕获列表。然后,您可以查看变量,看看它们是否有值

在这个例子中,我使用了/x标志来扩展正则表达式,使空白变得无关紧要,并允许内联注释。这样读起来容易一些,Perl在跨行扩展语句方面比Python宽松得多:

#!perl
use strict;
my $entry = '';
my ($name, $expense, $date_expense, $date_paid) =
    $entry =~ m/
        ^
        ( .+                      )  \s  # Name
        ( (?:\d+\.)?\d{1,3},\d{2} )  \s  # Expense
        ( \d{2}\.\d{2}\.\d{2}     )  \s  # Date
        ( \d{2}\.\d{2}\.\d{2}     )      # Date Paid
        $
        /x;

if( defined $name ) {
    print <<"HERE";
Name:      $name
Expense:   $expense
Date:      $date_expense
Date Paid: $date_paid
HERE
    }
else {
    print "No match!";
    }

但是,Perl也支持Python风格的捕获。不依赖于长正则表达式中的捕获位置,而是为每个捕获指定一个带有(?P<label>...)的名称(尽管大多数Perl人会将P省略为(?<label>...))。捕获名称是%+散列中的键:

#!perl
use strict;
my $entry = 'Test23242asdsa 800,03 23.05.19 22.05.19';
$entry =~ m/
        ^
        (?P<name>       .+                      )  \s
        (?P<expense>    (?:\d+\.)?\d{1,3},\d{2} )  \s
        (?P<date>       \d{2}\.\d{2}\.\d{2}     )  \s
        (?P<date_paid>  \d{2}\.\d{2}\.\d{2}     )
        $
        /x;

if( defined $+{name} ) {
    print <<"HERE";
Name:      $+{name}
Expense:   $+{expense}
Date:      $+{date}
Date Paid: $+{date_paid}
HERE
    }
else {
    print "No match!";
    }

相关问题 更多 >

    热门问题