我有一个正则表达式来测试CSV单元格是否包含正确的文件路径:
编辑 CSV列出了脚本运行时尚不存在的文件路径(我不能使用-e),文件路径可以包含*或%variable%或{$ variable}。
my $FILENAME_REGEXP = '^(|"|""")(?:[a-zA-Z]:[\\\/])?[\\\/]{0,2}(?:(?:[\w\s\.\*-]+|\{\$\w+}|%\w+%)[\\\/]{0,2})*\1$';
由于CSV单元格有时包含双引号的包装,有时文件名本身需要用双引号括起来,所以我进行了这种分组(|“|”“”)... \ 1
然后使用此功能:
sub ValidateUNCPath{
my $input = shift;
if ($input !~ /$FILENAME_REGEXP/){
return;
}
else{
return "This is a Valid File Path.";
}
}
我正在尝试测试这个短语是否与我的正则表达式相匹配(它应该不匹配):
"""c:\my\dir\lord"
但是亲爱的Perl在以下情况下进入无限循环:
ValidateUNCPath('"""c:\my\dir\lord"');
编辑实际上它会循环播放:
ValidateUNCPath('"""\aaaaaaaaa\bbbbbbb\ccccccc\Netwxn00.map"');
我确保在http://regexpal.com中我的正则表达式正确地捕获了那些包含双引号的非对称“”“...”,但Perl有了自己的想法:(
我甚至尝试了
中的/ g和/ o标志/$FILENAME_REGEXP/go
但它仍然悬而未决。我错过了什么?
答案 0 :(得分:3)
首先,你发布的任何内容都不会导致无限循环,所以如果你得到一个,那么它不会来自代码的这一部分。
当我尝试你的子程序时,对于远离看起来像路径的各种字符串,它返回true,例如:
.....
This is a Valid File Path.
.*.*
This is a Valid File Path.
-
This is a Valid File Path.
这是因为你的正则表达式相当松散。
^(|"|""") # can match the empty string
(?:[a-zA-Z]:[\\\/])? # same, matches 0-1 times
[\\\/]{0,2} # same, matches 0-2 times
(?:(?:[\w\s\.\*-]+|\{\$\w+}|%\w+%)[\\\/]?)+\1$ # only this is not optional
由于只有最后一部分实际上必须匹配任何东西,所以你允许所有类型的字符串,主要是在第一个字符类中:[\w\s\.\*-]
在我个人看来,当你开始依赖看起来像你的正则表达式时,你做错了什么。除非你熟练使用正则表达式,并且希望没有人不会被迫修复它。
为什么不删除引号?此外,如果系统中存在此路径,则可以更轻松地检查其是否有效:-e $path
答案 1 :(得分:1)
更新
编辑:从反复试验中,以下分组子表达式[\w\s.*-]+
导致回溯问题
(?:
(?:
[\w\s.*-]+
| \{\$\w+\}
| %\w+%
)
[\\\/]?
)+
修复#1, 展开的方法
'
^
( # Nothing
|" # Or, "
|""" # Or, """
)
# Here to end, there is no provision for quotes (")
(?: # If there are no balanced quotes, this will fail !!
[a-zA-Z]
:
[\\\/]
)?
[\\\/]{0,2}
(?:
[\w\s.*-]
| \{\$\w+\}
| %\w+%
)+
(?:
[\\\/]
(?:
[\w\s.*-]
| \{\$\w+\}
| %\w+%
)+
)*
[\\\/]?
\1
$
'
修复#2,独立子表达式
'
^
( # Nothing
|" # Or, "
|""" # Or, """
)
# Here to end, there is no provision for quotes (")
(?: # If there are no balanced quotes, this will fail !!
[a-zA-Z]
:
[\\\/]
)?
[\\\/]{0,2}
(?>
(?:
(?:
[\w\s.*-]+
| \{\$\w+\}
| %\w+%
)
[\\\/]?
)+
)
\1
$
'
修复#3,删除+量词(或添加+?)
'
^
( # Nothing
|" # Or, "
|""" # Or, """
)
# Here to end, there is no provision for quotes (")
(?: # If there are no balanced quotes, this will fail !!
[a-zA-Z]
:
[\\\/]
)?
[\\\/]{0,2}
(?:
(?:
[\w\s.*-]
| \{\$\w+\}
| %\w+%
)
[\\\/]?
)+
\1
$
'
答案 2 :(得分:1)
如果正则表达式引擎是天真的,
('y') x 20 =~ /^.*.*.*.*.*x/
由于必须尝试,需要很长时间才能失败
20 * 20 * 20 * 20 * 20 = 3,200,000 possible matches.
您的模式具有类似的结构,这意味着它有许多组件可以匹配您输入的各种子字符串。
现在,Perl的正则表达式引擎高度优化,远非天真。在上面的模式中,它将首先查找x
,然后非常快地退出。不幸的是,它没有或无法同样优化您的模式。
你的模式完全混乱。我甚至不打算猜测它匹配的假设。一旦切换到正确的模式,您会发现此问题将自行解决。
答案 3 :(得分:0)
感谢sln这是我的固定正则表达式:
my $FILENAME_REGEXP = '^(|"|""")(?:[a-zA-Z]:[\\\/])?[\\\/]{0,2}(?:(?:[\w\s.-]++|\{\$\w+\}|%\w+%)[\\\/]{0,2})*\*?[\w.-]*\1$';
(我也不允许在目录中使用* char,并且只允许使用单个* in(最后)文件名)