开发者

Inverse htmlentities / html_entity_decode

Basically I want to turn a string like this:

<code> &lt;div&gt; blabla &lt;/div&gt; </code>

into this:

&lt;code&gt; <div> blabla </div> &lt;/code&gt;

How can I do it?


The use case (bc some people were curious):

A page like this with a list of allowed HTML tags and examples. For example, <code> is a allowed tag, and this would be the sample:

<code>&lt;?php echo "Hello World!"; ?&gt;</code>

I wanted a reverse function because there are many such tags with samples that I store them all into a array which I iterate in one loop, instead of handling each one i开发者_开发技巧ndividually...


My version using regular expressions:

$string = '<code> &lt;div&gt; blabla &lt;/div&gt; </code>';
$new_string = preg_replace(
    '/(.*?)(<.*?>|$)/se', 
    'html_entity_decode("$1").htmlentities("$2")', 
    $string
);

It tries to match every tag and textnode and then apply htmlentities and html_entity_decode respectively.


There isn't an existing function, but have a look at this. So far I've only tested it on your example, but this function should work on all htmlentities

function html_entity_invert($string) {
    $matches = $store = array();
    preg_match_all('/(&(#?\w){2,6};)/', $string, $matches, PREG_SET_ORDER);

    foreach ($matches as $i => $match) {
        $key = '__STORED_ENTITY_' . $i . '__';
        $store[$key] = html_entity_decode($match[0]);
        $string = str_replace($match[0], $key, $string);
    }

    return str_replace(array_keys($store), $store, htmlentities($string));
}

Update:

  • Thanks to @Mike for taking the time to test my function with other strings. I've updated my regex from /(\&(.+)\;)/ to /(\&([^\&\;]+)\;)/ which should take care of the issue he raised.

  • I've also added {2,6} to limit the length of each match to reduce the possibility of false positives.

  • Changed regex from /(\&([^\&\;]+){2,6}\;)/ to /(&([^&;]+){2,6};)/ to remove unnecessary excaping.

  • Whooa, brainwave! Changed the regex from /(&([^&;]+){2,6};)/ to /(&(#?\w){2,6};)/ to reduce probability of false positives even further!


Replacing alone will not be good enough for you. Whether it be regular expressions or simple string replacing, because if you replace the &lt &gt signs then the < and > signs or vice versa you will end up with one encoding/decoding (all &lt and &gt or all < and > signs).

So if you want to do this, you will have to parse out one set (I chose to replace with a place holder) do a replace then put them back in and do another replace.

$str = "<code> &lt;div&gt; blabla &lt;/div&gt; </code>";
$search = array("&lt;","&gt;",);

//place holder for &lt; and &gt;
$replace = array("[","]");

//first replace to sub out &lt; and &gt; for [ and ] respectively
$str = str_replace($search, $replace, $str);

//second replace to get rid of original < and >
$search = array("<",">");
$replace = array("&lt;","&gt;",);
$str = str_replace($search, $replace, $str);

//third replace to turn [ and ] into < and >
$search = array("[","]");
$replace = array("<",">");

$str = str_replace($search, $replace, $str);

echo $str;


I think i have a small sollution, why not break html tags into an array and then compare and change if needed?

function invertHTML($str) {
    $res = array();
    for ($i=0, $j=0; $i < strlen($str); $i++) { 
        if ($str{$i} == "<") { 
           if (isset($res[$j]) && strlen($res[$j]) > 0){
                $j++; 
                $res[$j] = '';
           } else {
               $res[$j] = '';
           }
           $pos = strpos($str, ">", $i); 
           $res[$j] .= substr($str, $i, $pos - $i+1); 
           $i += ($pos - $i); 
           $j++;
           $res[$j] = '';
           continue; 
        } 
        $res[$j] .= $str{$i}; 
    } 

    $newString = '';
    foreach($res as $html){
        $change = html_entity_decode($html);
        if($change != $html){
            $newString .= $change;
        } else {
            $newString .= htmlentities($html);
        }
    }
    return $newString; 
}

Modified .... with no errors.


So, although other people on here have recommended regular expressions, which may be the absolute right way to go ... I wanted to post this, as it is sufficient for the question you asked.

Assuming that you are always using html'esque code:

 $str = '<code> &lt;div&gt; blabla &lt;/div&gt; </code>';
 xml_parse_into_struct(xml_parser_create(), $str, $nodes);
 $xmlArr = array();
 foreach($nodes as $node) { 
     echo htmlentities('<' . $node['tag'] . '>') . html_entity_decode($node['value']) . htmlentities('</' . $node['tag'] . '>');
 }

Gives me the following output:

&lt;CODE&gt; <div> blabla </div> &lt;/CODE&gt;

Fairly certain that this wouldn't support going backwards again .. as other solutions posted, would, in the sense of:

 $orig = '<code> &lt;div&gt; blabla &lt;/div&gt; </code>';
 $modified = '&lt;CODE&gt; <div> blabla </div> &lt;/CODE&gt;';
 $modifiedAgain = '<code> &lt;div&gt; blabla &lt;/div&gt; </code>';


I'd recommend using a regular expression, e.g. preg_replace():

  • http://www.php.net/manual/en/function.preg-replace.php

  • http://www.webcheatsheet.com/php/regular_expressions.php

  • http://davebrooks.wordpress.com/2009/04/22/php-preg_replace-some-useful-regular-expressions/


Edit: It appears that I haven't fully answered your question. There is no built-in PHP function to do what you want, but you can do find and replace with regular expressions or even simple expressions: str_replace, preg_replace

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜