[英]Perl regex substitution for a URL
我正在嘗試使用復雜的正則表達式來匹配文本正文中的URL。 目的是划分文本中的URL。
我想做類似下面的事情
perl -pe 's/regex/left $1 right/g;' inputfile
這將替換所有出現的正則表達式,其中left
和right
的單詞所包含的匹配值這只是一個簡單的例子來說明這一點 - 真實場景有大量的-e
表達式,我希望為這個特定的匹配添加另一個目的。
正則表達式與URL匹配。 我意識到匹配的URL是非常困難的,並且可能無法識別所有可能性,但合理的近似值會很好。 我在http://daringfireball.net/2010/07/improved_regex_for_matching_urls找到了一個這樣的近似值。
但是,我無法使用像上面這樣的perl構造中的正則表達式。 我嘗試過不同的分隔符而不是/
例如~
但沒有成功。
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
我找到了這個問題的答案,感謝另一個問題使用正則表達式從Perl中提取純文本的URL 。 這個URL比我之前嘗試的要簡單得多,但似乎在我測試過的簡單案例中起作用。
perl -i -pe 's,(http.*?://([^\s)\"](?!ttp:))+),left $& right,g;' myfile
匹配URL的正則表達式很容易變得難以管理:
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;
}
輸入Regexp :: Common :
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.