Регулярное выражение (в PHP), чтобы соответствовать и не являются объектами HTML

Вот цель: заменить все автономные амперсанды на & amp; но НЕ заменяйте те, которые уже являются частью сущности HTML, такие как & nbsp;.

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

5 ответов

Решение

Вы всегда можете бежать html_entity_decode прежде чем бежать htmlentities? Работает, если только вы не хотите использовать амперсанды (и даже тогда вы можете играть с параметрами набора символов).

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

РНР htmlentities() имеет double_encode аргумент для этого.

Если вы хотите делать подобные вещи в регулярных выражениях, тогда полезны отрицательные утверждения:

preg_replace('/&(?![a-z#]+;)/i','&',$txt);

Росс привел меня к хорошему ответу. Вот код, который, кажется, работает довольно хорошо. До сих пор.:-) Цель, опять же, конвертировать HTML в XML, в частности описания для RSS-каналов. В кратком тестировании, которое я провел до сих пор (с некоторыми довольно причудливыми данными), я смог взять строки, обернутые в CDATA, и развернуть их. Проходит валидационные испытания. Спасибо, Росс.

//decode all entities
$string=html_entity_decode($string,ENT_COMPAT,'UTF-8');

//entity-encode only &<> and double quotes
$string=htmlspecialchars($string,ENT_COMPAT,'UTF-8');

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

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

&                      # an ampersand
( \#                   # a '#' character
  [1-9]                # followed by a non-zero digit, 
  [0-9]{1,3}           # with between 2 and 4             (\d{1,3} or \p{IsDigit}{1,3})
| [A-Za-z]             # OR a letter                      (\p{IsAlpha})
  [0-9A-Za-z]+         # followed by letters or numbers   (\p{IsAlnum}+)
)
;                      # all capped with a ';'

Вы могли бы даже добавить туда кучу ожидаемых объектов, чтобы помочь сканеру регулярных выражений.

&                      # an ampersand
( amp | apos | gt | lt | nbsp | quot                 
                       # standard entities
| bull | hellip | [lr][ds]quo | [mn]dash | permil          
                       # some fancier ones
| \#                   # a '#' character
  [1-9]                # followed by a non-zero digit, 
  [0-9]{1,3}           # with between 2 and 4 
|  [A-Za-z]            # OR a letter
  [0-9A-Za-z]+         # followed by letters or numbers
)
;                      # all capped with a ';'

У меня была такая же проблема, изначально использовал:

$string = htmlspecialchars($string, ENT_QUOTES, "UTF-8", FALSE);

Но нужно было работать с PHP4 и набором CharSets, в итоге:


function htmlspecialchars_custom($string)
{
  $string = str_replace("\x05\x06", "", $string);
  $string = preg_replace("/&([a-z\d]{2,7}|#\d{2,5});/i", "\x05\x06$1", $string);
  $string = htmlspecialchars($string, ENT_QUOTES);
  $string = str_replace("\x05\x06", "&", $string);

  return $string;
}

Это не идеально, но достаточно хорошо для моих нужд.

Другие вопросы по тегам