4

複雑な正規表現を使用して、テキスト本文の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でそのような近似の1つを見つけました。

ただし、その正規表現を上記のようなperl構造で機能させることはできません。/たとえばとは異なる区切り文字を試してみまし~たが、成功しませんでした。

4

3 に答える 3

6

RFC 2396の付録Bには、URIを解析するための正規表現が記載されています。

B.正規表現を使用したURI参照の解析

セクション4.3で説明したように、一般的なURI構文は、一部の形式のURIのコンポーネントを明確にするのに十分ではありません。このセクションで説明する「欲張りアルゴリズム」は、POSIX正規表現で使用される曖昧さ回避方法と同じであるため、URI参照の潜在的な4つのコンポーネントとフラグメント識別子を解析するために正規表現を使用するのは自然で一般的です。

次の行は、URI参照をそのコンポーネントに分解するための正規表現です。

^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
 12            3  4          5       6  7        8 9

上記の2行目の数字は、読みやすくするためだけのものです。それらは、各部分式の参照点を示します(つまり、各ペアの括弧)。部分式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>、は、上記の例のクエリコンポーネントの場合のように、コンポーネントが存在しないことを示します。したがって、4つのコンポーネントとフラグメントの値を次のように決定できます。

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モジュールです。左と右の外接は簡単です

#! /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;
}

出力:

$猫の入力
これは、に適したプレーンテキスト入力です。
http://stackoverflow.comの質問への回答

特に、質問はで利用可能です
http://stackoverflow.com/q/15233535/123109とその答え
http://stackoverflow.com/a/15234378/123109で

$ ./mark-uris input
これは、に適したプレーンテキスト入力です。
左http://stackoverflow.com右の質問への回答

特に、質問はで利用可能です
左http://stackoverflow.com/q/15233535/123109右と答え
左http://stackoverflow.com/a/15234378/123109右
于 2013-03-05T21:23:06.033 に答える
2

別の質問のおかげで、この質問に対する答えを見つけました。正規表現を使用して、PerlでプレーンテキストからURLを抽出します。URLは以前に試したものよりもはるかに単純ですが、テストした単純なケースでは機能するようです。

perl -i -pe 's,(http.*?://([^\s)\"](?!ttp:))+),left $& right,g;' myfile
于 2013-03-05T20:47:44.313 に答える
1

一致する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
于 2013-03-05T22:29:59.677 に答える