http://~文字列を正規表現でリンクに置き換えたい - PHPプロ!Q&A掲示板

238

  • 300P

http://~文字列を正規表現でリンクに置き換えたい

質問日時 / 2006年11月17日 16:14    回答数 / 6件

Questioner:  atsushi  このエントリーをはてなブックマークに追加 

キーワード / 正規表現    preg_replace   

渡されてきたテキストの中にある「http://~」という文字列をpreg_replaceを使って
<a href="http://~">http://~</a>
という形に置き換えようと思っています。

ただ、渡されてきたテキストの中には最初から<a>タグで囲まれている部分も含まれているので、それは置き換えないようにしなければいけません。

たとえば、
http://www.google.com/
<a href="http://www.google.com/" >http://www.yahoo.co.jp/</a>
もしこんな文字列が渡されてきたら、

<a href="http://www.google.com/">http://www.google.com/</a>
<a href="http://www.google.com/" >http://www.yahoo.co.jp/</a>

上記のように変換したいのですが、<a>タグで囲まれている文字列を取得する正規表現は分かるのですが、<a>タグで囲まれていないhttp://~文字列を取得するという方法が分からずに困っています。どんな正規表現で実現できるか教えていただけないでしょうか。
よろしくお願いします。

この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。



ツリー一覧

┣A01galluがると申します。 んと…正規表現「のみ」でないとダ
┃┗A01-1atsushiご解答ありがとうございました。 確かに正規表現にこ
┣A02adAtype_kyouta$urlStr = 'http://www.google.com/' ; $urlStr =
┃┗A02-1atsushiご解答ありがとうございました。 ただ、この構文です
┗A03paradogs別の方の質問でも preg_replace_callback() を使う方
 ┗A03-1atsushiご解答ありがとうございました。 preg_replace_callb

回答一覧

並び替え:

A01 満足
answerergallu [11月17日 17:50]

がると申します。
んと…正規表現「のみ」でないとダメでしょうか?

もし「特にこだわりがない」ようであれば、以下の二段構えのやり方で出来るかなぁと思い、ちと書き込みなどしてみたく。
物凄く大雑把にコードもどきを書いて見ます。

@lists = a エレメントに囲まれたもの(<a href=""> ~ </a>)とそれ以外を正規表現で切り出す(切り出すデータ);
$ret = "";
foreach (@lists as $list) {
 // もし「aエレメントにかこまれたもの」ならそのまま次の処理へ
 if ($list == 「aエレメントにかこまれたもの」) {
  // まず足しこんで
  $ret .= $list;
  // 次の処理へ
  continue;
 }
 // ここからが本番
 // もしURLならAエレメントで囲い込んで足しこむ
 if ($list == URL) {
  // URLを囲い込む
  $list = sprintf("<a href='%s'>%s</a>", $list, $list);
 }
 // 足す
 $ret .= $list;
}

これで、$retには必要なものが入っているのではないかと思うのですが。
どうでしょうか?

この意見に回答する

ツリーへ TOPへ

A01-1
replyeratsushi [11月17日 18:37]

ご解答ありがとうございました。
確かに正規表現にこだわる必要は無いですね。
最初のちょっとした処理を正規表現で行ってその続きで書いていたので、なんとなく正規表現で一発で解決しようとしてました。
ご解答いただいたような処理で一度スクリプトを組んでみます。

この意見に回答する

ツリーへ TOPへ

A02
answereradAtype_kyouta [11月17日 18:16]

$urlStr = 'http://www.google.com/' ;

$urlStr = preg_replace ( '/((http|https):\/\/[0-9a-z-\/._?=&%\[\]~]+)/i', '<a href="\\1">\\1</a>', $urlStr ) ;

var_dump ( $urlStr ) ;


ざっくりとですがこれでどうでしょうか。
もっと細かく指定できそうですが・・・。

この意見に回答する

ツリーへ TOPへ

A02-1
replyeratsushi [11月17日 18:35]

ご解答ありがとうございました。
ただ、この構文ですと、

<a href="http://www.google.com/">http://www.google.com/</a>

のような文字列が渡された場合、

<a href="<a href="http://www.google.com/">http://www.google.com</a>"><a href="http://www.google.com/>htttp://www.google.com/</a>

こんなふうにタグの中にあるhttp://も変換されちゃうかと思います。
「http://~」の文字列をリンクに変換する処理も必要なのですが、その際にすでに<a>タグで囲まれている
「http://~」文字列を省く処理を入れなければならなくて困っていたところです。

この意見に回答する

ツリーへ TOPへ

A03 満足
answererparadogs [11月17日 18:40]

別の方の質問でも preg_replace_callback() を使う方法を紹介させて頂きましたが、
<a>...</a> と URL らしき文字列の両方にマッチさせ、コールバック関数でふるいにかければ一発でいけます。
# 正規表現の方はかなり適当で、URL に含めるべきでない文字も拾うので注意してください。
# ユーザからの入力をリンクする場合は htmlspecialchars() や urlencode() 等で処理しておく必要があります。
<?php
function urllink($match)
{
    if (!empty($match[1])) {
        return sprintf('<a href="%1$s">%1$s</a>', $match[1]);
    }
    return $match[0];
}
$str = <<<EOS
http://www.google.com/
<a href="http://www.google.com/">http://www.yahoo.co.jp/</a>
EOS;
echo preg_replace_callback('@<a\\s.*?>.*?</a>|(https?://[\\x21-\\x7E]+)@', 'urllink', $str);
?>

この意見に回答する

ツリーへ TOPへ

A03-1
replyeratsushi [11月17日 23:28]

ご解答ありがとうございました。
preg_replace_callbackを使ってなんとかうまく処理できました。
こんな感じになりました。

$str = 判別するHTML;
$str = preg_replace_callback("/(<a [^>]+?>.+?<\/a>)|(https?:\/\/[a-zA-Z0-9_\.\/\~\%\:\#\?=&\;\-]+)/i", "urllink", $str);
echo $str;

function urllink($match) {
  if ($match[1]) {
    // 最初から<a>タグで囲まれている場合
    if (preg_match("/<a .*?href *?= *\"(http[^\"]+?)\"[^>]*?>(.+?)<\/a>/i", $match[1], $matches)) {
      //  <a>タグの href属性が http から始まっている場合(javascript対策)
      return sprintf('<a href="%1$s" target="_blank" title="%2$s">%2$s</a>', htmlspecialchars($matches[1]), htmlspecialchars($matches[2]));
    } else {
      //  <a>タグの href属性が http から始まっていない場合はエスケープして出力
      return htmlspecialchars($match[1]);
    }
  } elseif ($match[2]) {
    // <a>タグで囲まれていないけど http://~ から始まっている場合
    return sprintf('<a href="%1$s" target="_blank" title="%1$s">%1$s</a>', htmlspecialchars($match[2]));
  }
}



hrefやonclickにjavascriptを入れられないようにちょっと処理も増やしてみました。
あとはURLの正規表現や動作をチェックして完成させたいと思います。
ありがとうございました。

この意見に回答する

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
PHPのHTML埋め込み記述について
 このエントリーをはてなブックマークに追加 
A
$_POST["data"] == "男" ? $val = "checked" : $val = "" ; の意味は以下と同じです。 if($_POST["data"] == "男"){ $val = "checked; } e...

>>続きを読む

kende様のご指摘通り、三項演算子を使用する際には、コードの複雑度などを考慮する必要がありますね。書きやすさと共に可読性も追求したいところですね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)