在PHP中但保留html标签的htmlentities

我想将string中的所有文本转换为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> 

有任何想法吗?

您可以通过函数get_html_translation_table获得htmlentities使用的对应字符列表=>实体。 考虑这个代码:

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

(您可能需要在手册中检查第二个参数 – 也许您需要将其设置为与默认值不同的值)

它会得到你这样的事情:

 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来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,我想 – 我试图find一个解决scheme,并将再次编辑)

第二次编辑几分钟后:看起来你必须在$search列表上使用utf8_encode ,然后调用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) 

这一次,应该是可以的^^
它并不真正适合一条线,可能不是最优化的解决scheme; 但它应该可以正常工作,并且具有允许您添加/删除任何对应字符=>您需要或不需要的实体的优点。

玩的开心 !

可能不是非常有效,但它的工作

 $sample = '<p><font style="color:#FF0000">Camión español</font></p>'; echo htmlspecialchars_decode( htmlentities($sample, ENT_NOQUOTES, 'UTF-8', false) , ENT_NOQUOTES ); 

这是接受的答案的优化版本。

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

没有解决scheme的解决scheme将是正确的所有情况下。 你的情况很好:

 <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> 

问题:您可以在构buildHTML之前进行编码。 换句话说可以这样做:

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

如果你能做到的话,你会为自己节省很多的痛苦。 如果你不能,你需要一些方法来跳过编码<,>和(如上所述),或者简单地编码它,然后撤消它(例如, replace('&lt;', '<')

这是我刚才写的一个函数,它以非常优雅的方式解决了这个问题:

首先,将从string中提取HTML标签,然后对每个剩余的子string执行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("@$sep@", $matches[0][$i], $tmp, 1); return $tmp; } 

根据bflesch的回答,我做了一些更改来pipe理包含less than signgreater than signsingle quotedouble quotes

 function htmlentitiesOutsideHTMLTags ($htmlText, $ent) { $matches = Array(); $sep = '###HTMLTAG###'; preg_match_all(":</{0,1}[az]+[^>]*>:i", $htmlText, $matches); $tmp = preg_replace(":</{0,1}[az]+[^>]*>: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手册传递任何ent flag

单行解决scheme,无需翻译表或自定义function:

我知道这是一个老问题,但我最近不得不导入一个静态网站到WordPress的网站,并不得不克服这个问题:

这里是我的解决scheme,不需要翻译转换表: htmlspecialchars_decode( htmlentities( html_entity_decode( $string ) ) );

当应用于OP的string时:

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

输出:

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

当应用于Luca的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> 

输出:

 <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> 

编辑:这工作特别好,首先“漂白”inputstring:

$string = preg_replace( '/[^\x00-\x7F]/', null, $string ); htmlspecialchars_decode( htmlentities( html_entity_decode( $string ) ) );

现在$string是太漂亮了!