对于我正在开发的应用程序,我需要一个Perl脚本,它循环遍历一个大量的CSV文件,并确保每一行包含一个有效的URI。我之前已经问过一个关于解析CSV文件的问题,我已经开始使用Text::CSV
来让我的生活更轻松。现在我遇到了确保URI有效的问题。
由于我的应用程序的性质,URI不需要采用完整形式的
protocol://username:password@domain.extension/request?vars=values
相反,我只对此请求部分感兴趣。对于一般网站,这可以是.com
,.edu
等之后的任何内容。
我目前有以下Perl脚本:
if($_ !~ /^(?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*$/i){
print "Invalid URL format";
exit;
} else {
/* stuff */
}
正则表达式应该是相当直接的。允许请求包含一小组符号([a-z0-9-._~!$&'()*+,;=:/?@]
)中的一个,或者它可以包含百分号(%
),后跟两个十六进制数字。这些模式中的任何一个都可以无限重复。
当我运行此脚本时,我收到以下错误:
Number found where operator expected at ./301rules.pl line 58, near "%[0"
(Missing operator before 0?)
Bareword found where operator expected at ./301rules.pl line 58, near "9A"
(Missing operator before A?)
Bareword found where operator expected at ./301rules.pl line 58, near "$/i"
(Missing operator before i?)
syntax error at ./301rules.pl line 58, near "%[0"
很明显,我的正则表达式中的某些内容需要被转义,但我不确定是什么。我尝试转义每个可能的符号来创建以下正则表达式:
if($_ !~ /^(?:[a-z0-9\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=\:\/\?\@]|%[0-9A-F]{2})*$/i){
然而,当我这样做时,它只允许每个字符串通过测试,即使是我知道无效的字符串,例如te%st
或é
那么有没有人有Perl正则表达式的经验,知道我需要逃避什么以及我不应该逃避什么?有了19个不同的符号,我不想尝试所有2 ^ 19 = 524288的可能性。
编辑 - 投票结束。我发现问题实际上存在于此循环之上,尽管我还不完全理解为什么。
我有:
if( $_ == "" ){
next;
}
/* regex conditional from above */
无论出于何种原因,尽管明确存储在$_
中的数据,但它仍然继续评估为真并进入下一次迭代。我会弄清楚为什么会这样,但是现在这个正则表达式可以正常运行。
答案 0 :(得分:5)
在URI
module的文档中,我发现了以下内容:
使用REGEXP PARSING URI
作为这个模块的替代品, 以下(官方)定期 表达式可用于解码a URI:
my($scheme, $authority, $path, $query, $fragment) = $uri =~ m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;
URI :: Split模块提供了 函数uri_split()作为可读的替代方案。
但我认为Regexp::Common::URI可能是HTTP URI语法验证的理想解决方案。
use Regexp::Common qw /URI/;
while (<>) {
/$RE{URI}{HTTP}/ and print "Contains an HTTP URI.\n";
}
任何由达米安写的并由阿比盖尔维护的东西都必须受到启发,伟大,疯狂或以上所有。 (我的意思是尽可能高的。)
答案 1 :(得分:2)
我不知道你是如何得到你的第一个正则表达式,但我会尽力帮助你解决这个问题。你只需要逃避正则表达式中具有特殊含义的字符 - 从你的正则表达式,它们是: - ,。,$,(,),*,/,所以正则表达式应该是这样的:
if($_ !~ /^(?:[a-z0-9\-\._~!\$&'\(\)\*+,;=:\/?@]|%[0-9A-F]{2})*$/i){
我并不完全知道?:
试图在那里实现什么,但是你的第一个字符类(第一个[]
之间的表达式)没有任何乘数 - 也许它应该跟一个*,a +或a?另外,我认为|
符号意味着在您的第一个字符类和第or
前面的第二个字符类之间执行%
- 正如它现在看起来那样,它是在它之间进行的第一个字符类和%
符号。它可能应该像|(%[0-9A-F]{2}))*$
答案 2 :(得分:-1)
您应该使用rfc regexp来检查每个可能的字符。看this