我的文本文件包含以下行:
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 = '?'
,然后将?
替换为{{1} }在$q
字符串分配(即"
)中编译并运行脚本。如果我在$pat = "/^\s*(\S+)\s+($q:[0-9|\)| ]+)+\s+([0-9|.|,]+)\s+\$/";
块外分配了正则表达式字符串,那么它也可以正常工作。 Perl v5.26.1。
我的代码中也没有任何switch/case
,正如编译失败所报告的那样,可能是}continue
将switch/case
代码转换为本地代码的某种形式。编译器阻塞。这是Switch.pm中的某种错误吗?即使我以完全相同的方式使用Switch.pm
也会失败。
given/when
答案 0 :(得分:4)
请勿使用Switch
。正如@choroba在评论中所提到的那样,Switch
使用了源过滤器,这导致了您所构造的神秘且难以调试的错误。
该模块的文档本身说:
通常,使用给定/时间代替。它是在perl 5.10.0中引入的。 Perl 5.10.0于2007年发布。
但是,given/when
不一定是一个好的选择,因为它是实验性的,并且将来可能会发生变化(此功能似乎是almost removed来自Perl v5.28;因此,您肯定不会这样做)如果您可以避免的话,现在就想开始使用它)。一个不错的选择是使用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/.../
而不是/.../
。
我不知道为什么会发生此错误,但是documentation说:
此外,是否存在用原始?...?指定的正则表达式。分隔符可能会导致神秘的错误。解决方法是使用m?...?代替。
我一开始就读错了,因此尝试使用m/../
而不是/../
来解决此问题。
答案 1 :(得分:2)
另一个代替if
/ elsif
链的选择是遍历散列,该散列将您的正则表达式映射到应分配给$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;
}
}
对于更一般的情况(即,如果您要做的不仅仅是将标量分配给字符串),您可以使用相同的通用技术,但将coderefs用作哈希值,从而允许它执行基于匹配的任意sub
。
此方法可以涵盖通常与switch
/ case
构造相关的相当广泛的功能,但请注意,由于条件是从哈希键中提取的,因此可以以随机顺序进行评估。如果您的数据可以匹配多个条件,则需要采取额外的预防措施来进行处理,例如以条件的正确顺序并行排列数组,或使用Tie::IxHash代替常规哈希。