Для тех, кому интересно, как работает регулярное выражение Алана Мура (и да, оно работает ), я позволил себе прокомментировать его, чтобы его могли прочитать простые смертные:
function process_data_alan($text) //
{
$re = '%# Collapse ws everywhere but in blacklisted elements.
(?> # Match all whitespans other than single space.
[^\S ]\s* # Either one [\t\r\n\f\v] and zero or more ws,
| \s{2,} # or two or more consecutive-any-whitespace.
) # Note: The remaining regex consumes no text at all...
(?= # Ensure we are not in a blacklist tag.
(?: # Begin (unnecessary) group.
(?: # Zero or more of...
[^<]++ # Either one or more non-"<"
| < # or a < starting a non-blacklist tag.
(?!/?(?:textarea|pre)\b)
)*+ # (This could be "unroll-the-loop"ified.)
) # End (unnecessary) group.
(?: # Begin alternation group.
< # Either a blacklist start tag.
(?>textarea|pre)\b
| \z # or end of file.
) # End alternation group.
) # If we made it here, we are not in a blacklist tag.
%ix';
$text = preg_replace($re, " ", $text);
return $text;
}
Я здесь новичок, но сразу вижу, что Алан довольно хорош в регулярных выражениях. Я бы только добавил следующие предложения.
- Существует ненужная группа захвата, которую можно удалить.
- Хотя ОП не сказал об этом, элемент
<SCRIPT>
должен быть добавлен в черный список <PRE>
и <TEXTAREA>
.
- Добавление модификатора "Study"
'S'
PCRE ускоряет это регулярное выражение примерно на 20%.
- В прогнозной группе есть альтернативная группа, которая готова применить эффективную конструкцию Фридла " unrolling-the-loop ".
- На более серьезном замечании, та же самая группа альтернатив: (то есть
(?:[^<]++|<(?!/?(?:textarea|pre)\b))*+
) подвержена чрезмерной рекурсии PCRE для больших целевых строк, что может привести к переполнению стека, в результате чего исполняемый файл Apache / PHP молча ошибка сегмента и сбой без предупреждения. (Win32-сборка Apache httpd.exe
особенно восприимчива к этому, потому что она имеет стек только 256 КБ по сравнению с исполняемыми файлами * nix, которые обычно создаются со стеком 8 МБ или более.) Филипп Хейзел (автор механизма регулярных выражений PCRE, используемого в PHP) обсуждает эту проблему в документации: PCRE ОБСУЖДЕНИЕ ИСПОЛЬЗОВАНИЯ STACK . Хотя Алан правильно применил то же исправление, что и Филип, который показывает в этом документе (применяя притяжательный плюс к первому варианту), все равно будет много рекурсии, если файл HTML большой и содержит много не внесенных в черный список тегов. например На моем Win32-боксе (с исполняемым файлом со стеком 256 КБ) сценарий взрывается с тестовым файлом размером всего 60 КБ. Также обратите внимание, что PHP, к сожалению, не следует рекомендациям и устанавливает слишком большой предел рекурсии по умолчанию, равный 100000. (Согласно документам PCRE это должно быть установлено равным размеру стека, деленному на 500).
Вот улучшенная версия, которая работает быстрее оригинала, обрабатывает больший ввод и изящно завершается с сообщением, если входная строка слишком велика для обработки:
// Set PCRE recursion limit to sane value = STACKSIZE / 500
// ini_set("pcre.recursion_limit", "524"); // 256KB stack. Win32 Apache
ini_set("pcre.recursion_limit", "16777"); // 8MB stack. *nix
function process_data_jmr1($text) //
{
$re = '%# Collapse whitespace everywhere but in blacklisted elements.
(?> # Match all whitespans other than single space.
[^\S ]\s* # Either one [\t\r\n\f\v] and zero or more ws,
| \s{2,} # or two or more consecutive-any-whitespace.
) # Note: The remaining regex consumes no text at all...
(?= # Ensure we are not in a blacklist tag.
[^<]*+ # Either zero or more non-"<" {normal*}
(?: # Begin {(special normal*)*} construct
< # or a < starting a non-blacklist tag.
(?!/?(?:textarea|pre|script)\b)
[^<]*+ # more non-"<" {normal*}
)*+ # Finish "unrolling-the-loop"
(?: # Begin alternation group.
< # Either a blacklist start tag.
(?>textarea|pre|script)\b
| \z # or end of file.
) # End alternation group.
) # If we made it here, we are not in a blacklist tag.
%Six';
$text = preg_replace($re, " ", $text);
if ($text === null) exit("PCRE Error! File too big.\n");
return $text;
}
p.s. Мне хорошо знакома эта проблема с ошибками сегментов в PHP / Apache, поскольку я помогал сообществу Drupal, пока они боролись с этой проблемой. См .: Оптимизация опции CSS приводит к сбою php cgi в функции pcre "match" . Мы также испытали это с анализатором BBCode в программном проекте форума FluxBB.
Надеюсь, это поможет.