如果文件名包含破折号,perl 会出现问题

如果文件名包含破折号,perl 会出现问题
... | perl -pe "s/([^$filespec]*)($filespec)/ ...

$filespec所以我有一个函数,如果大多数情况下,上述结构都可以正常工作。然而如果文件名中有破折号我收到一条Invalid [] range消息。

如何确保变量$filespec扩展为不受此类解析错误影响的文件名?

答案1

关键假设 -$filespec只是您想要匹配的一组字符。这是不是一个正则表达式。

让我们用一些代码来模拟这个问题

filespec = 'z-a'
perl -e 'print "MATCH\n" if "DEF" =~ /$filespec/'

use strict;
use warnings;

my $filespec = 'z-a';

print "Match\n" if "DEF" =~ m/[^$filespec]/ ;

跑步可以给

Invalid [] range "z-a" in regex; marked by <-- HERE in m/[^z-a <-- HERE ]/ at try line 6.

$filespec当正则表达式中的 扩展为 时,会触发该问题m/[^z-a]/。在这种情况下z-a是无效的字符范围。

要解决此问题,您需要(至少)转义-in $filespec。使用quotemeta应该可以解决问题,就像这样

use strict;
use warnings;

my $filespec = quotemeta 'z-a';

print "Match\n" if "DEF" =~ m/[^$filespec]/ ;

输出是

Match

将其包含到管道命令的模拟中。首先是失败的命令版本

filespec='z-a'
perl -e "print qq[MATCH\n] if 'DEF' =~ /[^$filespec]/"

跑步给

Invalid [] range "z-a" in regex; marked by <-- HERE in m/[^z-a <-- HERE ]/ at -e line 1.

这是固定版本

filespec='z-a'; 
filespec=`perl -e "print quotemeta qq[$filespec]"`
perl -e "print qq[MATCH\n] if 'DEF' =~ /[^$filespec]/"

答案2

括号表达式中的破折号被视为范围,除非它用反斜杠1转义或者是表达式中的第一个或最后一个字符(或者,如果用^后面的第一个字符^或最后一个字符对表达式进行否定)。

例如

[a-z]匹配从a到 的所有小写字符z (但请参阅注释 2)

[a\-z][-az][az-]全部仅匹配 3 个字符:-az

并且,正如 @pmqs 在他们的答案中指出的那样,[z-a]这是一个无效范围,并且会生成错误。

如果您的正则表达式包含带有一个或多个破折号的括号表达式,那么您需要对其进行修改,以便它按您的预期工作。与大多数事情一样,您需要充分了解您正在使用的软件和语言功能,以使它们执行您想要/期望的操作。

请参阅man perlre参考资料 来了解有关 perl 正则表达式的详细信息,包括便利功能和您需要注意的其他“陷阱”。该手册页中有很多内容,您不可能一下子掌握所有内容。当您需要时再回顾一下,您将在未来几年内更多地了解它的工作原理。另请参阅man perlrequick快速参考和man perlretut教程。有关man perlrecharclassperl 中的字符类和括号表达式的更多信息。有关man perlrebackslashPerl 中反斜杠和转义序列的更多信息。

(如果您的 linux 发行版或 unix 没有可用作man页面的 perl 文档,则使用perldoc作为运行命令,而不是man,例如perldoc perlre)。

鉴于 Perl 有五个主要手册页,总计约 54000 字的散文和示例,专门用于正则表达式(还有两个您可能永远不需要的:perlreguts描述 perl 正则表达式引擎如何工作和perlreapi描述 perlre 的插件接口),您可能会开始猜测这是一个复杂的话题 - 你是对的。


笔记:

1并非所有正则表达式引擎都支持括号表达式内的转义字符。 Perl 可以,但大多数不可以 - 例如 GNU grep 的 BRE(默认,或-G)和 ERE ( -E) 不可以,但 GNU grep 的 perl 兼容 ( -P) 正则表达式可以。

2 [[:alpha:]][[:upper:]]或者[[:lower:]]通常更适合匹配字母字符,因为它们可以处理 unicode 文本以及纯 ASCII。[[:alnum:]]与字母数字字符一样。

相关内容