我有包含以下行的文本文件:
2/17/2018 400000098627 =2,000.0 $2.0994 $4,387.75
3/7/2018 1)0000006043 2,000.0 $2.0731 $4,332.78
3/26/2018 4 )0000034242 2,000.0 $2.1729 $4,541.36
4/17/2018 2)0000008516 2,000.0 $2.219 $4,637.71
我将它们与/^\s*(\S+)\s+(?:[0-9|\)| ]+)+\s+([0-9|.|,]+)\s+\$/
匹配但是我也有一些文件的行以完全不同的格式,我匹配不同的正则表达式。当我打开文件时,我确定哪种格式并在switch / case块中分配$pat = '<regex-string>';
:
$pat = '/^\s*(\S+)\s+(?:[0-9|\)| ]+)+\s+([0-9|.|,]+)\s+\$/'
但引入非捕获组的?
字符用于匹配日期之后和第一个货币金额之前的重复,导致Perl解释器无法编译脚本,报告中止:
syntax error at ./report-dates-amounts line 28, near "}continue "
如果我删除?
字符,或用?
转义字符替换\?
,或首先分配$q = '?'
然后在?
字符串赋值(即.$q
)中用"
替换$pat = "/^\s*(\S+)\s+($q:[0-9|\)| ]+)+\s+([0-9|.|,]+)\s+\$/";
脚本编译并运行。如果我在switch/case
块之外分配正则表达式字符串也可以正常工作。 Perl v5.26.1。
我的代码中也没有任何}continue
,正如编译失败中所报告的那样,可能是switch/case
将Switch.pm
代码转换为编译器扼杀的本地代码。这是Switch.pm中的某种错误吗?即使我以完全相同的方式使用given/when
它也会失败。
#!/usr/local/bin/perl
use Switch;
# Edited for demo
switch($format)
{
# Format A eg:
# 2/17/2018 400000098627 =2,000.0 $2.0994 $4,387.75
# 3/7/2018 1)0000006043 2,000.0 $2.0731 $4,332.78
# 3/26/2018 4 )0000034242 2,000.0 $2.1729 $4,541.36
# 4/17/2018 2)0000008516 2,000.0 $2.219 $4,637.71
#
case /^(?:april|snow)$/i
{ # This is where the ? character breaks compilation:
$pat = '^\s*(\S+)\s+(?:[0-9|\)| ]+)+\s+\D?(\S+)\s+\$';
# WORKS:
# $pat = '^\s*(\S+)\s+(' .$q. ':[0-9|\)| ]+)+\s+\D' .$q. '(\S+)\s+\$';
}
# Format B
case /^(?:umberto|petro)$/i
{
$pat = '^(\S+)\s+.*Think 1\s+(\S+)\s+';
}
}
不要使用qazxsw poi。正如@choroba在评论中提到的那样,qazxsw poi使用了一个源过滤器,当你建立时,它会导致神秘且难以调试的错误。
该模块的文档本身说:
一般来说,使用given / when代替。它是在perl 5.10.0中引入的。 Perl 5.10.0于2007年发布。
然而,Switch
不一定是一个很好的选择,因为它是实验性的,并且可能在未来发生变化(似乎这个功能是来自Perl v5.28的Switch
;所以如果你能避免的话,你绝对不想开始使用它它)。一个很好的选择是使用given/when
:
almost removed
它可能看起来很奇怪,但是一旦你习惯它,我认为它实际上是合理的。或者,当然,您不能使用这些选项,只需执行以下操作:
for
如果由于某种原因,你仍然想使用for ($format) {
if (/^(?:april|snow)$/i) {
...
}
elsif (/^(?:umberto|petro)$/i) {
...
}
}
:使用sub pattern_from_format {
my $format = shift;
if ($format =~ /^(?:april|snow)$/i) {
return qr/^\s*(\S+)\s+(?:[0-9|\)| ]+)+\s+\D?(\S+)\s+\$/;
}
elsif ($format =~ /^(?:umberto|petro)$/i) {
return qr/^(\S+)\s+.*Think 1\s+(\S+)\s+/;
}
# Some error handling here maybe
}
而不是Switch
。
我不知道为什么会发生这个错误,但是,m/.../
说:
还有,用raw指定的正则表达式的存在?...?分隔符可能会导致神秘的错误。解决方法是使用m?...?代替。
我最初误读,因此试图使用/.../
而不是documentation,这解决了这个问题。
另一个选择而不是m/../
/ /../
链将循环遍历哈希,哈希将正则表达式映射到应分配给if
的值:
elsif
对于更一般的情况(即,如果你做的不仅仅是将字符串分配给标量),你可以使用相同的通用技术,但使用coderefs作为哈希的值,从而允许它执行基于任意的$pat
在比赛中。
这种方法可以涵盖通常与#!/usr/local/bin/perl
my %switch = (
'^(?:april|snow)$' => '^\s*(\S+)\s+(?:[0-9|\)| ]+)+\s+\D?(\S+)\s+\$',
'^(?:umberto|petro)$' => '^(\S+)\s+.*Think 1\s+(\S+)\s+',
);
for my $re (keys %switch) {
if ($format =~ /$re/i) {
$pat = $switch{$re};
last;
}
}
/ sub
结构相关的各种功能,但请注意,由于条件是从哈希的键中提取的,因此它们将以随机顺序进行评估。如果您有可以匹配多个条件的数据,则需要采取额外的预防措施来处理该问题,例如使用具有正确顺序的条件的并行数组或使用switch
而不是常规哈希。