Предупреждение: preg_replace (): Неизвестный модификатор ']'

У меня есть следующая ошибка:

Предупреждение: preg_replace (): Неизвестный модификатор ']' в xxx.php в строке 38

Это код в строке 38:

<?php echo str_replace("</ul></div>", "", preg_replace("<div[^>]*><ul[^>]*>", "", wp_nav_menu(array('theme_location' => 'nav', 'echo' => false)) )); ?> 

Может кто-то, пожалуйста, помогите мне решить эту проблему?

Почему возникает ошибка

В PHP регулярное выражение должно быть заключено в пару разделителей . Разделителем может быть любой небуквенный символ, не обратный слэш, не-пробельный символ; / , # , ~ являются наиболее часто используемыми. Обратите внимание, что также можно использовать разделители стиля скобок, где открывающие и закрывающие скобки являются начальным и конечным разделителем, т.е. <pattern_goes_here> , [pattern_goes_here] и т. Д. Все действуют.

Ошибка « Неизвестный модификатор X » обычно возникает в следующих двух случаях:

  • Когда в вашем регулярном выражении отсутствуют разделители .

  • Когда вы используете разделитель внутри шаблона, не избегая его.

В этом случае регулярное выражение <div[^>]*><ul[^>]*> . Механизм регулярных выражений рассматривает все от < to > как шаблон регулярного выражения, а потом все как модификаторы.

 Regex: <div[^> ]*><ul[^>]*> │ │ │ │ └──┬──┘ └────┬─────┘ pattern modifiers 

] здесь неизвестный модификатор, потому что он появляется после закрытия > разделителя. Именно поэтому PHP генерирует эту ошибку.

В зависимости от шаблона, неизвестная жалоба-модификатор также могла быть о * , + , p , / или ) или почти любой другой букве / символе. Только imsxeADSUXJu являются действительными модификаторами PCRE .

Как это исправить

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

 ~<div[^>]*><ul[^>]*>~ │ │ │ └─ ending delimiter └───────────────────── starting delimiter 

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

Или разделители исключений

/foo[^/]+bar/i , безусловно, вызовет ошибку. Таким образом, вы можете избежать этого, используя \ backslash, если он появляется в любом месте регулярного выражения:

 /foo[^\/]+bar/i │ │ │ └──────┼─────┴─ actual delimiters └─────── escaped slash(/) character 

Это утомительная работа, если ваш шаблон регулярного выражения содержит так много вхождений символа разделителя.

Разумеется, более чистым способом было бы использовать другой разделитель. В идеале символ, который не появляется нигде внутри шаблона регулярного выражения, скажем ##foo[^/]+bar#i .

Больше информации:

  • Ограничения регулярного выражения PHP
  • http://www.regular-expressions.info/php.html
  • Как преобразовать выражения ereg в preg в PHP? (отсутствующие разделители)
  • Неизвестный модификатор '/' in …? что это? (при использовании preg_quote() )

Другие примеры

Справочный ответ уже объясняет причину предупреждений «Неизвестный модификатор». Это просто сравнение других типичных вариантов.

  • Когда вы забываете добавлять регулярные выражения / разделители / , первый небуквенный символ будет считаться одним. Поэтому предупреждение часто о том, что следует за группировкой (…) , […] метасимволом:

     preg_match("[a-zA-Z]+:\s*.$" ↑ ↑⬆ 
  • Иногда ваше регулярное выражение уже использует пользовательский разделитель ( : здесь), но по-прежнему содержит тот же символ, что и неэкранированный литерал. Это ошибочно считается преждевременным разделителем. Вот почему следующий символ получает трофей «Неизвестный модификатор»:

     preg_match(":\[[\d:/]+\]:" ↑ ⬆ ↑ 
  • При использовании классического / разделителя, будьте осторожны, чтобы не иметь его в регулярном выражении буквально. Это чаще всего происходит при попытке сопоставления имен файлов без имени :

     preg_match("/pathname/filename/i" ↑ ⬆ ↑ 

    Или при сопоставлении тегов стиля угла / квадрата:

     preg_match("/<%tmpl:id>(.*)</%tmpl:id>/Ui" ↑ ⬆ ↑ 
  • Шаблоны регулярных выражений (Smarty или BBCode) часто требуют скобки {…} или […] . Оба они обычно должны быть экранированы. (Исключением является внешняя {} пара).

    Они также ошибочно интерпретируются как парные разделители, когда фактический разделитель не используется. Если они тогда также используются как буквальный символ внутри, то это, конечно … ошибка.

     preg_match("{bold[^}]+}" ↑ ⬆ ↑ 
  • Всякий раз, когда в предупреждении говорится, что « разделитель не должен быть буквенно-цифровым или обратным слэшем », вы также полностью забыли разделители:

     preg_match("ab?c*" ↑ 
  • « Неизвестный модификатор« g »часто указывает регулярное выражение, которое было скопировано дословно из JavaScript или Perl.

     preg_match("/abc+/g" ⬆ 

    PHP не использует глобальный флаг /g . Вместо этого функция preg_replace работает во всех вхождениях, а preg_match_all – это «глобальный» поисковый кулон для одного события preg_match .

    Итак, просто удалите флаг /g .

    Смотрите также:
    · Предупреждение: preg_replace (): Неизвестный модификатор 'g'
    · Preg_replace: bad regex == 'Неизвестный модификатор'?

  • Более странный случай относится к значку PCRE_EXTENDED /x . Это часто (или должно быть) используется для создания более эффективных и читаемых регулярных выражений.

    Это позволяет использовать встроенные комментарии # . PHP реализует разделители регулярных выражений поверх PCRE. Но он не обрабатывает # каким-либо особым образом. Вот как буквальный разделитель в # комментарии может стать ошибкой:

     preg_match("/ ab?c+ # Comment with / slash in between /x" 

    (Также следует отметить, что использование # как #abc+#x разделителя может быть вдвойне нецелесообразным).

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

      preg_match("/id=$var;/" ↑ ↺ ↑ 

    В таких случаях лучше всего применить $var = preg_quote($var, "/") .

    Смотрите также:
    · Неизвестный модификатор '/' в …? что это?

    Другой альтернативой является использование \Q…\E экранов для строк без кавычек:

      preg_match("/id=\Q{$var}\E;/mix"); 

    Обратите внимание, что это просто удобный ярлык, не надежный / безопасный. Он распался бы, если бы $var содержал буквальный '\E' (хотя и маловероятный).

  • Устаревший модификатор / e – совершенно другая проблема. Это не имеет ничего общего с разделителями, но режим интерпретации неявных выражений постепенно прекращается. См. Также: Заменить устаревшие preg_replace / e с preg_replace_callback

Альтернативные разделители регулярных выражений

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

  • ~abc+~
  • !abc+!
  • @abc+@
  • #abc+#
  • =abc+=
  • %abc+%

Технически вы можете использовать $abc$ или |abc| для разделителей. Тем не менее, лучше избегать символов, которые служат метасимволами регулярного выражения.

Хеш # как разделитель тоже довольно популярен. Но следует соблюдать осторожность в сочетании с модификатором удобочитаемости x / PCRE_EXTENDED . Вы не можете использовать комментарии # inline или (?#…) , потому что они будут смущены как разделители.

Ограничители только для цитирования

Иногда вы видите " и ' используемые в качестве разделителей регулярных выражений в сочетании с их conterpart как оболочкой строки PHP:

  preg_match("'abc+'" preg_match('"abc+"' 

Что совершенно верно для PHP. Это иногда удобно и ненавязчиво, но не всегда разборчиво в IDE и редакторах.

Сопряженные разделители

Интересным вариантом являются парные разделители. Вместо того, чтобы использовать один и тот же символ на обоих концах регулярного выражения, вы можете использовать любую комбинацию <...> (...) [...] {...} скобок / фигурных скобок.

  preg_match("(abc+)" # just delimiters here, not a capture group 

Хотя большинство из них также служат метасимволами регулярных выражений, вы можете часто использовать их без дополнительных усилий. Пока эти конкретные фигурные скобки / parens внутри регулярного выражения спарены или экранированы правильно, эти варианты вполне читаемы.

Необычные разделители регулярных выражений

Несколько ленивый трюк (который не поддерживается настоящим) использует непечатаемые символы ASCII в качестве разделителей. Это легко работает в PHP, используя двойные кавычки для строки регулярных выражений и восьмеричные escape-последовательности для разделителей:

  preg_match("\001 abc+ \001mix" 

\001 – это только контрольный символ ␁, который обычно не требуется. Поэтому он вряд ли появится в большинстве шаблонов регулярных выражений. Это делает его подходящим здесь, хотя и не очень разборчивым.

К сожалению, вы не можете использовать символы Unicode качестве разделителей. PHP допускает только однобайтовые символы. И почему так? Ну, рад, что вы спросили:

Разметки PHP на вершине PCRE

В preg_* используется механизм регулярного выражения PCRE , который сам по себе не заботится или не предусматривает разделителей. Для сходства с Perl функции preg_* реализуют их. Именно поэтому вы можете использовать буквы-модификаторы /ism вместо констант в качестве параметра .

См. Ext / pcre / php_pcre.c о том, как строка регулярных выражений предварительно обрабатывается:

  • Сначала все ведущие пробелы игнорируются.

  • В качестве предполагаемого разделителя принимается любой символ, отличный от алфавита. Обратите внимание, что PHP выполняет только однобайтовые символы:

     delimiter = *p++; if (isalnum((int)*(unsigned char *)&delimiter) || delimiter == '\\') { php_error_docref(NULL,E_WARNING, "Delimiter must not…"); return NULL; } 
  • Остальная строка регулярного выражения перемещается влево-вправо. Символы с обратной косой чертой игнорируются.

  • Если разграничитель будет найден снова, остаток проверяется только на букву модификатора.

  • Если разделитель является одним из ([{< )]}> )]}> скрытых скобок / скобок, то логика обработки более сложна.

     int brackets = 1; /* brackets nesting level */ while (*pp != 0) { if (*pp == '\\' && pp[1] != 0) pp++; else if (*pp == end_delimiter && --brackets <= 0) break; else if (*pp == start_delimiter) brackets++; pp++; } 

    Он ищет правильно спаренный левый и правый разделитель, но при подсчете игнорирует другие фигурные скобки / типы скобок.

  • Необработанная строка регулярных выражений передается на сервер PCRE только после того, как флаги-разделители и флаги-модификаторы были вырезаны.

Теперь все это несколько не имеет значения. Но объясняет, откуда берутся предупреждения с разделителями. И вся эта процедура должна иметь минимум совместимости с Perl. Конечно, есть несколько незначительных отклонений, например, контекст класса символа […] не получающий специального лечения в PHP.

Другие ссылки

  • preg_match (); – Неизвестный модификатор '+'
  • Неизвестная ошибка модификатора '/' в PHP
  • Ошибка PHP RegExpr Unkown modifier '('
  • Неизвестный модификатор '(' при использовании preg_match () с выражением REGEX
  • PHP: Regex – неизвестная ошибка модификатора
  • Предупреждение: preg_match () [function.preg-match]: Неизвестный модификатор '('
  • Когда выполняется preg_match (): Неизвестная ошибка модификатора?
    (Просто хорошо написанный вопрос, демонстрирующий предыдущие исследования)