web-dev-qa-db-ja.com

PHP内のhtmlエンティティですが、htmlタグを保持しています

文字列内のすべてのテキストをhtmlエンティティに変換しますが、HTMLタグは保持します。たとえば、次のようにします。

<p><font style="color:#FF0000">Camión español</font></p>

これに翻訳する必要があります:

<p><font style="color:#FF0000">Cami&oacute;n espa&ntilde;ol</font></p>

何か案は?

54
fidoboy

対応する文字のリストを取得できます文字=> htmlentities で使用されるエンティティ、関数 get_html_translation_table ;このコードを検討してください:

$list = get_html_translation_table(HTML_ENTITIES);
var_dump($list);

(マニュアルのその関数の2番目のパラメーターを確認する必要があるかもしれません-多分それをデフォルトのものとは異なる値に設定する必要があるでしょう)

それはあなたにこのようなものを得るでしょう:

array
  ' ' => string '&nbsp;' (length=6)
  '¡' => string '&iexcl;' (length=7)
  '¢' => string '&cent;' (length=6)
  '£' => string '&pound;' (length=7)
  '¤' => string '&curren;' (length=8)
  ....
  ....
  ....
  'ÿ' => string '&yuml;' (length=6)
  '"' => string '&quot;' (length=6)
  '<' => string '&lt;' (length=4)
  '>' => string '&gt;' (length=4)
  '&' => string '&amp;' (length=5)

次に、不要な対応を削除します。

unset($list['"']);
unset($list['<']);
unset($list['>']);
unset($list['&']);

これで、リストには、エンコードしたくないいくつかの文字を除いて、htmlentitesで使用されるすべての対応文字=>エンティティが含まれています。

そして今、あなたはただキーと値のリストを抽出する必要があります:

$search = array_keys($list);
$values = array_values($list);

そして最後に、str_replaceを使用して置換を行うことができます。

$str_in = '<p><font style="color:#FF0000">Camión español</font></p>';
$str_out = str_replace($search, $values, $str_in);
var_dump($str_out);

そしてあなたは得る:

string '<p><font style="color:#FF0000">Cami&Atilde;&sup3;n espa&Atilde;&plusmn;ol</font></p>' (length=84)

あなたが望んだもののように見えます;-)


編集:まあ、エンコードの問題を除いて(UTF-8はいまいましい、私はその解決策を見つけようとしているので、もう一度編集します)

数分後の2番目の編集:utf8_encodeを呼び出す前に、$searchリストでstr_replaceを使用する必要があるようです。

これは次のようなものを使用することを意味します:

$search = array_map('utf8_encode', $search);

array_keysの呼び出しとstr_replaceの呼び出しの間。

そして、今回は、本当に欲しいものを手に入れるべきです:

string '<p><font style="color:#FF0000">Cami&oacute;n espa&ntilde;ol</font></p>' (length=70)


そして、これがコードの完全な部分です:

$list = get_html_translation_table(HTML_ENTITIES);
unset($list['"']);
unset($list['<']);
unset($list['>']);
unset($list['&']);

$search = array_keys($list);
$values = array_values($list);
$search = array_map('utf8_encode', $search);

$str_in = '<p><font style="color:#FF0000">Camión español</font></p>';
$str_out = str_replace($search, $values, $str_in);
var_dump($str_in, $str_out);

そして完全な出力:

string '<p><font style="color:#FF0000">Camión español</font></p>' (length=58)
string '<p><font style="color:#FF0000">Cami&oacute;n espa&ntilde;ol</font></p>' (length=70)

今回は大丈夫だと思います^^
実際には1行に収まらず、最適化されたソリューションではない可能性があります。しかし、それは正常に機能するはずであり、必要なかどうかにかかわらず、対応する文字=>エンティティを追加/削除できるという利点があります。

楽しんで !

64
Pascal MARTIN

それほど効率的ではないかもしれませんが、機能します

$sample = '<p><font style="color:#FF0000">Camión español</font></p>';

echo htmlspecialchars_decode(
    htmlentities($sample, ENT_NOQUOTES, 'UTF-8', false)
  , ENT_NOQUOTES
);
18
Peter Bailey

これは、受け入れられた回答の最適化バージョンです。

$list = get_html_translation_table(HTML_ENTITIES);
unset($list['"']);
unset($list['<']);
unset($list['>']);
unset($list['&']);

$string = strtr($string, $list);
7
SileNT

パーサーに不足している解決策は、すべての場合に正しくなることはありません。あなたは良い例です:

_<p><font style="color:#FF0000">Camión español</font></p>
_

しかし、あなたもサポートしたいですか:

_<p><font>true if 5 < a && name == "joe"</font></p>
_

あなたがそれを出て欲しい場所:

_<p><font>true if 5 &lt; a &amp;&amp; name == &quot;joe&quot;</font></p>
_

質問:HTMLを構築する前にエンコードを実行できますか?つまり、次のようなことができます。

_"<p><font>" + htmlentities(inner) + "</font></p>"
_

それができれば、多くの悲しみを救うでしょう。できない場合は、<、>、および "(上記のように)のエンコードをスキップするか、単にすべてをエンコードしてから元に戻す(例:replace('&lt;', '<'))ための方法が必要です。

5
ndp

これは私が書いたばかりの関数で、この問題を非常にエレガントな方法で解決します。

まず、HTMLタグが文字列から抽出され、残りのすべての部分文字列に対してhtmlentities()が実行されます。その後、元のHTMLタグが元の位置に挿入されるため、HTMLタグは変更されません。 :-)

楽しんで:

function htmlentitiesOutsideHTMLTags ($htmlText)
{
    $matches = Array();
    $sep = '###HTMLTAG###';

    preg_match_all("@<[^>]*>@", $htmlText, $matches);   
    $tmp = preg_replace("@(<[^>]*>)@", $sep, $htmlText);
    $tmp = explode($sep, $tmp);

    for ($i=0; $i<count($tmp); $i++)
        $tmp[$i] = htmlentities($tmp[$i]);

    $tmp = join($sep, $tmp);

    for ($i=0; $i<count($matches[0]); $i++)
        $tmp = preg_replace("@[email protected]", $matches[0][$i], $tmp, 1);

    return $tmp;
}
3
bflesch

bflesch の回答に基づいて、less than signgreater than signおよびsingle quoteまたはdouble quotesを含む文字列を管理するためにいくつかの変更を行いました。

function htmlentitiesOutsideHTMLTags ($htmlText, $ent)
{
    $matches = Array();
    $sep = '###HTMLTAG###';

    preg_match_all(":</{0,1}[a-z]+[^>]*>:i", $htmlText, $matches);

    $tmp = preg_replace(":</{0,1}[a-z]+[^>]*>:i", $sep, $htmlText);
    $tmp = explode($sep, $tmp);

    for ($i=0; $i<count($tmp); $i++)
        $tmp[$i] = htmlentities($tmp[$i], $ent, 'UTF-8', false);

    $tmp = join($sep, $tmp);

    for ($i=0; $i<count($matches[0]); $i++)
        $tmp = preg_replace(":$sep:", $matches[0][$i], $tmp, 1);

    return $tmp;
}



使用例:

$string = '<b>Is 1 < 4?</b>è<br><i>"then"</i> <div style="some:style;"><p>gain some <strong>€</strong><img src="/some/path" /></p></div>';
$string_entities = htmlentitiesOutsideHTMLTags($string, ENT_QUOTES | ENT_HTML401);
var_dump( $string_entities );

出力は次のとおりです。

string '<b>Is 1 &lt; 4?</b>&egrave;<br><i>&quot;then&quot;</i> <div style="some:style;"><p>gain some <strong>&euro;</strong><img src="/some/path" /></p></div>' (length=150)



htmlentities manual に従って、任意のent flagを渡すことができます

2
Luca Borrione

変換テーブルまたはカスタム関数が不要な1行のソリューション:

私はこれが古い質問であることを知っていますが、最近wordpressサイトに静的サイトをインポートする必要があり、この問題を克服する必要がありました:

これは、変換テーブルをいじる必要のない私の解決策です:

htmlspecialchars_decode( htmlentities( html_entity_decode( $string ) ) );

oPの文字列に適用される場合:

<p><font style="color:#FF0000">Camión español</font></p>

出力:

<p><font style="color:#FF0000">Cami&oacute;n espa&ntilde;ol</font></p>

ルカの文字列に適用すると:

<b>Is 1 < 4?</b>è<br><i>"then"</i> <div style="some:style;"><p>gain some <strong>€</strong><img src="/some/path" /></p></div>

出力:

<b>Is 1 < 4?</b>&egrave;<br><i>"then"</i> <div style="some:style;"><p>gain some <strong>&euro;</strong><img src="/some/path" /></p></div>
1
aequalsb