12

textarea input($_POST['content'])から、すべてのURLをリンクに変換しようとしています。

$content = preg_replace('!(\s|^)((https?://)+[a-z0-9_./?=&-]+)!i', ' <a href="$2" target="_blank">$2</a> ', nl2br($_POST['content'])." ");
$content = preg_replace('!(\s|^)((www\.)+[a-z0-9_./?=&-]+)!i', '<a target="_blank" href="http://$2"  target="_blank">$2</a> ', $content." ");

ターゲットリンクフォーマット:www.hello.comまたはhttp(s)://(www).hello.com

しかし、これはiframe、画像などを壊すようです、

HTMLタグのURLを無視する正しい正規表現はどのようになっていますか?

注:2つの式が必要なことはわかっています。1つはプロトコルリンクを検出しないwww.hello.comため(たとえば、先頭に追加する必要があります)、もう1つはプロトコルを使用してURLを検出するため(先頭に追加する必要はありません)です。

4

4 に答える 4

18

"iframe内などでは、パターンに応じてスペースではなくURLの前に通常のコードがあるため、コード自体はそれほど問題にはなりません。

ただし、ここでは別の解決策があります。<単一または>HTML内のコメントなどがある場合は、100%機能しない可能性があります。しかし、それ以外の場合は、うまく機能するはずです(そして、これがあなたにとって問題であるかどうかはわかりません)。>ネガティブ先読みを使用して、開く前に閉じないことを確認し<ます(これは、タグの内側にいることを意味するため)。

$content = preg_replace('$(\s|^)(https?://[a-z0-9_./?=&-]+)(?![^<>]*>)$i', ' <a href="$2" target="_blank">$2</a> ', $content." ");
$content = preg_replace('$(\s|^)(www\.[a-z0-9_./?=&-]+)(?![^<>]*>)$i', '<a target="_blank" href="http://$2"  target="_blank">$2</a> ', $content." ");

この手法に慣れていない場合は、もう少し詳しく説明します。

(?!        # starts the lookahead assertion; now your pattern will only match, if this subpattern does not match
[^<>]      # any character that is neither < nor >; the > is not strictly necessary but might help for optimization
*          # arbitrary many of those characters (but in a row; so not a single < or > in between)
>          # the closing >
)          # ends the lookahead subpattern

現在、正規表現内で使用しているため、正規表現の区切り文字を変更したことに注意してください!

タグの外側のURLにも最初のサブパターンが必要でない限り(\s|^)、それも削除できるようになりました(そして、置換のキャプチャ変数を減らします)。

$content = preg_replace('$(https?://[a-z0-9_./?=&-]+)(?![^<>]*>)$i', ' <a href="$1" target="_blank">$1</a> ', $content." ");
$content = preg_replace('$(www\.[a-z0-9_./?=&-]+)(?![^<>]*>)$i', '<a target="_blank" href="http://$1"  target="_blank">$1</a> ', $content." ");

そして最後に...最後にアンカーを含むURLを置き換えないつもりですか?例www.hello.com/index.html#section1?誤ってこれを見逃した場合は#、許可されたURL文字にを追加してください。

$content = preg_replace('$(https?://[a-z0-9_./?=&#-]+)(?![^<>]*>)$i', ' <a href="$1" target="_blank">$1</a> ', $content." ");
$content = preg_replace('$(www\.[a-z0-9_./?=&#-]+)(?![^<>]*>)$i', '<a target="_blank" href="http://$1"  target="_blank">$1</a> ', $content." ");

編集:また、どう+ですか%?エンコードせずにURLに表示できる文字は他にもいくつかあります。これを参照してください。 編集終了

私はこれがあなたのためのトリックをするべきだと思います。ただし、(お持ちのコードを使用して)機能するURLと壊れたURLを示す例を提供できれば、すべてのケースで機能するようにテストされたソリューションを実際に提供できます。

最後に1つ考えます。適切な解決策は、DOMパーサーを使用することです。次に、すでに持っている正規表現をテキストノードにのみ適用できます。ただし、HTML構造に対する懸念は非常に制限されているため、問題は再び定期的になります(HTMLコメントまたはページ上のJavaScriptまたはCSSに一致しない「<」または「>」がない限り)。これらの特殊なケースがある場合は、実際にDOMパーサーを調べる必要があります。その場合、ここで提示されているソリューションはどれも(これまでのところ)安全ではありません。

于 2012-09-25T20:45:59.607 に答える
17
  1. 私の意見では、URLはhttps?://、スペースまたは行の終わり(垂直スペースまたはいわゆる改行)で始まり、スペースで終わるすべてのものです。
  2. 最初のポイントのため、画像、リンクなどはすべて「または>」で始まるため、置き換えられません(リンクがスペースで始まる場合を除き<a href=" http...">ますが、これは無効なhtmlです)。
  3. 修飾子/mは、すべての行に一致するように正規表現に指示します(最初のポイントで説明された一致が機能するように)。
  4. 関数nl2br()は置換後に使用する必要があります(行の先頭から始まるリンクのため)。
  5. 前後のスペースは、スペースが元々$ contentに存在する場合にのみ追加されます(preg_replace()関数の2番目のパラメーターの$1と$3を参照)。
  6. このソリューションは、 www.moški.siのような特殊文字を含むドメイン名をサポートします

入力:

入力

コード:

<?php

$content =
    preg_replace(
        '~(\s|^)(https?://.+?)(\s|$)~im', 
        '$1<a href="$2" target="_blank">$2</a>$3', 
        $content
    );
$content = 
    preg_replace(
        '~(\s|^)(www\..+?)(\s|$)~im', 
        '$1<a href="http://$2" target="_blank">$2</a>$3', 
        $content
    );
$content = nl2br($content);

出力:

出力

編集:

https?://プレフィックスのないリンクの例+単一preg_replace()呼び出しの例(パターンと置換は配列です):

$content = 
    preg_replace(
        array(
            '~(\s|^)(www\..+?)(\s|$)~im', 
            '~(\s|^)(https?://)(.+?)(\s|$)~im', 
        ),
        array(
            '$1http://$2$3', 
            '$1<a href="$2$3" target="_blank">$3</a>$4', 
        ),
        $content
    );
$content = nl2br($content);

ここに画像の説明を入力してください

于 2012-09-25T22:07:11.497 に答える
3

それほど単純ではないことを提案させてください。入力テキストをhtml部分と非html部分に分割してから、非html部分を正規表現で処理してテキストを1つの部分に結合します。Smth。お気に入り:

  <?php
  $chunks = preg_split('/(<.*>)/Ums', $_POST['content'], -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  $result = '';
  foreach ($chunks as $chunk) {
    if (substr($chunk,0,1) != '<') {
      /* do your processing on $chunk */
    }
    $result .= $chunk;
  }

いくつかの追加のアドバイス:

  1. ソーステキストを保存し、それを表示するときに変換を実行してみてください。これにより、将来新しい問題/アイデアを見つけた場合に、レンダリングコードを改善/修正することができます。
  2. (https?//)+は角かっこで囲む必要はなく、+は必要ありません。これは、「https:// https://some.com」と一致するためです。https?://[a-z0 -9 _./?=&-] +
  3. (www。)+についても同じです:)
于 2012-09-21T22:18:35.703 に答える
3

これはこれまで何百回も行われてきました。このページでは、グリビックの短い表現が好きですが、 m-buettnerglavićのどちらでも問題なく動作します。

これを行うための優れたphpリソースは次のとおりです:http: //code.iamcal.com/php/lib_autolink/

Stackoverflowで繰り返します:

まともな詳細な記事: -http: //buildinternet.com/2010/05/how-to-automatically-linkify-text-with-php-regular-expressions/

于 2012-10-01T14:45:50.757 に答える