簡體   English   中英

Perl正則表達式替換URL

[英]Perl regex substitution for a URL

我正在嘗試使用復雜的正則表達式來匹配文本正文中的URL。 目的是划分文本中的URL。

我想做類似下面的事情

perl -pe 's/regex/left $1 right/g;' inputfile

這將替換所有出現的正則表達式,其中leftright的單詞所包含的匹配值這只是一個簡單的例子來說明這一點 - 真實場景有大量的-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM