我正在尝试使用复杂的正则表达式来匹配文本正文中的URL。目的是划分文本中的URL。
我想做类似下面的事情
perl -pe 's/regex/left $1 right/g;' inputfile
将用词left
和right
所包围的匹配值替换所有出现的正则表达式。这只是一个简单的例子来说明这一点 - 真实场景的载荷为{{1我希望为这个特定的匹配目的添加另一个表达式。
正则表达式与URL匹配。我意识到匹配的URL是非常困难的,并且可能无法识别所有可能性,但合理的近似值会很好。我在http://daringfireball.net/2010/07/improved_regex_for_matching_urls找到了一个这样的近似值。
但是,我不能将正则表达式用于像上面这样的perl构造中。我尝试使用与-e
不同的分隔符,例如/
,但没有成功。
答案 0 :(得分:5)
RFC 2396的附录B给出了解析URI的正则表达式。
B中。使用正则表达式解析URI引用
如第4.3节所述,通用URI语法不足以消除某些形式的URI的组件歧义。由于该部分中描述的“贪婪算法”与POSIX正则表达式使用的消歧方法相同,因此使用正则表达式来解析URI引用的潜在四个组件和片段标识符是很自然和平常的。
以下行是用于将URI引用分解为其组件的正则表达式。
^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? 12 3 4 5 6 7 8 9
上面第二行中的数字只是为了提高可读性;它们表示每个子表达式的参考点(即,每个配对括号)。我们将子表达式匹配的值 n 称为
匹配$<n>
。例如,将上述表达式与http://www.ics.uci.edu/pub/ietf/uri/#Related
导致以下子表达式匹配:
$1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 = <undefined> $7 = <undefined> $8 = #Related $9 = Related
其中
<undefined>
表示该组件不存在,如上例中的查询组件的情况。因此,我们可以确定四个组件和片段的值为scheme = $2 authority = $4 path = $5 query = $7 fragment = $9
并且,在相反的方向上,我们可以使用第5.2节的步骤7中的算法从其组件重新创建URI引用。
正则表达式可直接在Perl中使用,如
if ($uri =~ m!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!) {
my($host,$path) = ($4,$5);
print "$host => $path\n";
}
正则表达式量词的贪婪可能会使这种模式难以与s///
一起使用,因为它会消耗尽可能多的文本,可能会超出未标记的URI边界。
更直接适用的是CPAN上提供的URI::Find模块。围绕LEFT和RIGHT就像
一样简单#! /usr/bin/env perl
use strict;
use warnings;
use URI::Find;
my $finder = URI::Find->new(sub {
my(undef,$found) = @_;
"LEFT $found RIGHT";
});
while (<>) {
$finder->find(\$_);
print;
}
输出:
$ cat input This is a plain text input suitable for an answer to a question on http://stackoverflow.com In particular, the question is available at http://stackoverflow.com/q/15233535/123109 and the answer at http://stackoverflow.com/a/15234378/123109 $ ./mark-uris input This is a plain text input suitable for an answer to a question on LEFT http://stackoverflow.com RIGHT In particular, the question is available at LEFT http://stackoverflow.com/q/15233535/123109 RIGHT and the answer at LEFT http://stackoverflow.com/a/15234378/123109 RIGHT
答案 1 :(得分:2)
由于另一个问题Using regex to extract URLs from plain text with Perl,我找到了这个问题的答案。这个URL比我之前尝试的要简单得多,但似乎在我测试过的简单案例中起作用。
perl -i -pe 's,(http.*?://([^\s)\"](?!ttp:))+),left $& right,g;' myfile
答案 2 :(得分:1)
匹配网址的正则表达式很容易变得无法管理:
my @urls;
while ($body =~ m{
(
(ftp|https?):\/\/
([a-z0-9\-_]+(:[^@]+)?\@)?
(
([a-z0-9\.\-]+)\.([a-z\.]{2,6})
|
([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})
)
(:[0-9]{2,5})?
(
[a-z0-9\.\-_/\+\%&;\:,\=\!@\(\)\[\]~\'\"]*
[a-z0-9\.\-_/\+\%&;\:,\=\!@\(\)\[\]~]+
)
(\?[a-z0-9\.\-_/\+\%&;\:,\=\!@\(\)\[\]~]*)?
(\#[a-z0-9\.\-_/\+\%&;\:,\=\!@\(\)\[\]~]*)?
)
}gisx) {
push @urls => $1;
}
use Regexp::Common qw(URI);
my @urls;
while ($body =~ m{($RE{URI}{HTTP})}gos) {
push @urls => $1;
}
所以,要解决你的具体情况:
perl -MRegexp::Common=URI -pe 's/($RE{URI}{HTTP})/left $1 right/gos' inputfile