Обратные htmlentities / html_entity_decode - PullRequest
11 голосов
/ 12 июля 2011

В основном я хочу превратить строку, подобную этой:

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

в это:

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

Какя могу это сделать?


Вариант использования (bc некоторым людям было любопытно):

Страница типа эта со спискомразрешенных HTML-тегов и примеров.Например, <code> является разрешенным тегом, и это будет пример:

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

Я хотел использовать обратную функцию, потому что есть много таких тегов с образцами, которые я сохраняю все в массив, который яповторять в одном цикле, вместо того, чтобы обрабатывать каждый в отдельности ...

Ответы [ 7 ]

4 голосов
/ 17 июля 2011

Моя версия с использованием регулярных выражений:

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

Он пытается сопоставить каждый тег и текстовый узел и затем применить htmlentities и html_entity_decode соответственно.

4 голосов
/ 16 июля 2011

Не существует функции, но посмотрите на это. До сих пор я тестировал его только на вашем примере, но эта функция должна работать на 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));
}

Обновление:

  • Спасибо @ Mike за то, что нашли время проверить мою функцию с другими строками. Я обновил свое регулярное выражение с /(\&(.+)\;)/ до /(\&([^\&\;]+)\;)/, что должно решить проблему, которую он поднял.

  • Я также добавил {2,6}, чтобы ограничить длину каждого совпадения, чтобы уменьшить вероятность ложных срабатываний.

  • Изменено регулярное выражение с /(\&([^\&\;]+){2,6}\;)/ на /(&([^&;]+){2,6};)/ для удаления ненужных исключений.

  • Воуу, мозговая волна! Изменено регулярное выражение с /(&([^&;]+){2,6};)/ на /(&(#?\w){2,6};)/, чтобы уменьшить вероятность ложных срабатываний еще больше !

1 голос
/ 17 июля 2011

Итак, хотя другие люди здесь рекомендуют регулярные выражения, что может быть абсолютно правильным способом ... Я хотел опубликовать это, так как этого достаточно для вопроса, который вы задали.

Предполагая, чточто вы всегда используете 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'] . '>');
 }

Дает мне следующий вывод:

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

Совершенно уверен, что это не будет поддерживать возврат назад ... как другие решенияопубликовал бы, в смысле:

 $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>';
1 голос
/ 17 июля 2011

Я думаю, что у меня есть небольшое решение, почему бы не разбить HTML-теги на массивы, а затем сравнить и изменить при необходимости?

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

Изменено .... без ошибок.

1 голос
/ 12 июля 2011

Замена в одиночку не будет достаточно для вас.Будь то регулярные выражения или простая замена строк, потому что если вы заменяете знаки <>, то знаки <и> или наоборот, в итоге вы получите одну кодировку / декодирование (все знаки <и> или все знаки <и>).

Так что, если вы хотите сделать это, вам придется разобрать один комплект (я решил заменить его заполнителем), сделать замену, затем положить их обратно и сделать другую замену.

$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;
0 голосов
/ 12 июля 2011

Я бы рекомендовал использовать регулярное выражение, например, preg_replace ():

0 голосов
/ 12 июля 2011

Редактировать: Похоже, я не полностью ответил на ваш вопрос. Не существует встроенной функции PHP, которая делает то, что вы хотите, но вы можете найти и заменить регулярными выражениями или даже простыми выражениями: str_replace , preg_replace

...