php preg_replace regex lookahead - PullRequest
       26

php preg_replace regex lookahead

0 голосов
/ 21 октября 2011

Я пытаюсь заменить амперсанды в моем html по всей ширине, используя preg_replace, но проблема в том, что он ломает встроенный javascript && или URL-адрес javascript как? Page = test & id = 1

Теперь у меня есть этот код, который работает

$amp_replace = array();
$amp_replace[0] = '/(?<=\s)&(?!&)(?!#?[a-z0-9]+;)/';
$amp_replace[1] = '/(?<!&)&(?=\s)/';
$skin = preg_replace($amp_replace, '&amp;', $skin);

Заменяет амперсанды при наличии свободного места слева или справа.не заменяйте, когда 2 амперсанда в строке (для javascript) или когда следует html-сущность.

Но я нахожу здесь довольно ненужную логику.Он также не заменяет амперсанды, если это похоже на «test & test».

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

Не было бы лучшепросто заменить все амперсанды, если не в тегах сценария JavaScript?Я попробовал это уже, но без особого успеха

Кто-нибудь знает, как я могу заархивировать это?Спасибо

Ответы [ 2 ]

1 голос
/ 22 октября 2011

Если вы просто хотите конвертировать '&' в content и избегать тегов (т. Е. Значений атрибутов)
и избегайте блоков скриптов, что-то вроде ниже будет работать для большинства случаев.
Однако следует отметить, что значения атрибутов также должны быть преобразованы.
И для этого требуется гораздо больше работы.

Рабочий образец http://www.ideone.com/9MhCq

<?php

$html=<<<EOD
 <some &ta&g> S&P &&more; and &some; <more> &notme;
  && &#209; &#xa92F;
 <script flavor?>
   val && this & this 
 </script>
 &
EOD;

$rxent = '(?:&(?:[A-Za-z_:][\w:.-]*|\#(?:[0-9]+|x[0-9a-fA-F]+));)';

$rxtag =
'<
 (?:
     \?php\s+.*?\?
  |  (?:
       (?:
           (?:script|style)\s*
         | (?:script|style)\s+(?:".*?"|\'.*?\'|[^>]*?)+\s*
       )> .*? </(?:script|style)\s*
     )
  |  (?:
         /?[A-Za-z_:][\w:.-]*\s*/?
       |  [A-Za-z_:][\w:.-]*\s+(?:".*?"|\'.*?\'|[^>]*?)+\s*/?
       | !(?:DOCTYPE.*?|--.*?--)
     )
 )
 >
';

$rxmain = "~(?xs:((?:$rxtag)+) | ((?!$rxent)&))~";


print "$html\n\n";

$html = preg_replace_callback($rxmain, 'fixamp_cb', $html);

print "$html\n";

function fixamp_cb( $matches ) {
    # Return tags and script blocks unchanged.
    if (isset($matches[1]) && $matches[1])
       return $matches[1];
    return '&amp;';
}

?>
0 голосов
/ 21 октября 2011

Почему бы не сделать что-то простое, например:

$html = preg_replace('/([^&])&([^&])/', '$1&amp;$2', $html);

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

$html = preg_split('/<\/?script>/', $html);
foreach ($html as $k => $v) {
  if ($piece[0] == "<") {
    $html[$k] = preg_replace('/([^&])&([^&])/', '$1&amp;$2', $v);
  } else {
    $html[$k] = "<script>" . $html[$k] . "</script>";
}

Это потребует некоторой модификации, если теги сценария имеют атрибуты.

Если вы очищаете пользовательский контент, тогдаВы могли бы быть лучше, используя инструменты, которые уже доступны.См. Очиститель HTML

...