У меня есть следующая ошибка:
Предупреждение: 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 регулярное выражение должно быть заключено в пару delimiters. Разделителем может быть любой небуквенный символ, не обратный слэш, не-пробельный символ; /
, #
, ~
являются наиболее часто используемыми. Обратите внимание, что также можно использовать ограничители стиля скобок, где открывающие и закрывающие скобки являются начальным и конечным разделителем, то есть <pattern_goes_here>
, [pattern_goes_here]
и т.д. Все действительны.
Ошибка "Неизвестный модификатор X" обычно возникает в следующих двух случаях:
Когда ваше регулярное выражение отсутствует разделители.
Когда вы используете разделитель внутри шаблона без экранирования.
В этом случае регулярное выражение <div[^>]*><ul[^>]*>
. Механизм регулярных выражений рассматривает все от <
до >
как шаблон регулярного выражения, а затем все как модификаторы.
Regex: <div[^> ]*><ul[^>]*>
│ │ │ │
└──┬──┘ └────┬─────┘
pattern modifiers
]
здесь неизвестный модификатор, поскольку он появляется после закрывающего разделителя >
. Вот почему PHP генерирует эту ошибку.
В зависимости от шаблона жалоба неизвестного модификатора могла бы быть примерно *
, +
, p
, /
или )
или почти любой другой буквы/символа. Только imsxeADSUXJu
являются действительными модификаторами PCRE.
Исправить легко. Просто оберните шаблон регулярного выражения любыми действительными разделителями. В этом случае вы можете выбрать ~ и получить следующее:
~<div[^>]*><ul[^>]*>~
│ │
│ └─ ending delimiter
└───────────────────── starting delimiter
Если вы получаете эту ошибку, несмотря на использование разделителя, возможно, это связано с тем, что сам шаблон содержит несвязанные вхождения указанного разделителя.
/foo[^/]+bar/i
, безусловно, вызовет ошибку. Таким образом, вы можете избежать этого с помощью обратного слэша \, если он появляется где-нибудь в пределах регулярного выражения:
/foo[^\/]+bar/i
│ │ │
└──────┼─────┴─ actual delimiters
└─────── escaped slash(/) character
Это утомительная работа, если ваш шаблон регулярного выражения содержит так много вхождений символа разделителя.
Более чистый способ, конечно, состоял бы в том, чтобы использовать другой разделитель вообще. В идеале символ, который не появляется нигде внутри шаблона регулярного выражения, скажем #
- #foo[^/]+bar#i
.
preg_quote()
)preg_quote()
, то есть что-то вроде preg_replace('/'.preg_quote('/').'/i','',$string);
выдает такую же ошибку по теме. preg_quote()
слэш не должен быть экранирован preg_quote()
?
ereg
до preg_match
. Пришлось ввести разделители.
Ссылочный ответ уже объясняет причину появления предупреждений "Неизвестный модификатор". Это просто сравнение других типичных вариантов.
Если вы забудете добавить регулярное выражение /
разделители /
, первый небуквенный символ будет считаться одним. Поэтому предупреждение часто о том, что следует за метасимволом группировки (…)
, […]
:
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
может быть вдвойне нежелательно.)
Для интерполяции переменных в регулярное выражение требуется, чтобы они были предварительно -escaped или действительными регулярными выражениями. Вы не можете заранее сказать, сработает ли это:
preg_match("/id=$var;/"
↑ ↺ ↑
В таких случаях лучше всего применять $var = preg_quote($var, "/")
.
Смотрите также:
· Неизвестный модификатор '/' в...? что это?
Другая альтернатива - использование escape-символов \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
или (?#…)
Комментарии тогда, потому что они будут перепутаны как разделители.
Иногда вы видите, что "
и '
используются в качестве разделителей регулярных выражений в паре со своим контрагентом в виде строкового вложения PHP:
preg_match("'abc+'"
preg_match('"abc+"'
Что совершенно верно в отношении PHP. Иногда это удобно и ненавязчиво, но не всегда разборчиво в IDE и редакторах.
Интересным вариантом являются парные разделители. Вместо использования одного и того же символа на обоих концах регулярного выражения вы можете использовать любую комбинацию <...>
(...)
[...]
{...}
скобок/фигурных скобок.
preg_match("(abc+)" # just delimiters here, not a capture group
Хотя большинство из них также служат метасимволами регулярных выражений, вы часто можете использовать их без дополнительных усилий. Пока эти конкретные скобки/парены в регулярном выражении соединены или экранированы правильно, эти варианты вполне читабельны.
Несколько ленивый трюк (который не подтверждается) использует непечатаемые символы ASCII в качестве разделителей. Это легко работает в PHP, используя двойные кавычки для строки регулярного выражения и восьмеричные экранирующие символы для разделителей:
preg_match("\001 abc+ \001mix"
\001
- это просто управляющий символ ␁, который обычно не требуется. Поэтому маловероятно, что он появится в большинстве шаблонов регулярных выражений. Что делает его здесь подходящим, хотя и не очень разборчивым.
К сожалению, вы не можете использовать символы Юникода ❚
качестве разделителей. PHP допускает только однобайтовые символы. И почему так? Хорошо, рад, что вы спросили:
В preg_*
используется механизм регулярных выражений PCRE, который сам по себе не заботится о разделителях и не предоставляет их. Для сходства с Perl их preg_*
функции preg_*
. Вот почему вы также можете использовать буквы-модификаторы /ism
вместо констант в качестве параметра.
Смотрите ext/pcre/php_pcre.c о том, как строка regex предварительно обрабатывается:
Сначала игнорируются все ведущие пробелы.
Любой не буквенно-цифровой символ принимается как предполагаемый разделитель. Обратите внимание, что PHP учитывает только однобайтовые символы:
delimiter = *p++;
if (isalnum((int)*(unsigned char *)&delimiter) || delimiter == '\\') {
php_error_docref(NULL,E_WARNING, "Delimiter must not…");
return NULL;
}
Остальная часть строки регулярного выражения проходит слева направо. Только символы обратной косой черты \\
-escaped игнорируются. \Q
и \E
не приветствуется.
Если разделитель будет найден снова, проверяется, что остаток содержит только буквы-модификаторы.
Если в качестве разделителя используется одна из ([{< )]}> )]}>
скобок/скобок, то логика обработки более сложна.
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.
Если вы хотите получить исключение (InvalidPatternException
) вместо предупреждений или использования preg_last_error()
- рассмотрите возможность использования библиотеки T-Regx:
<?php
try
{
return pattern('invalid] pattern')->match($s)->all();
}
catch (InvalidPatternException $e)
{
// your pattern was invalid
}
Если вы хотите получить исключение (InvalidPatternException
) вместо предупреждений - рассмотрите возможность использования библиотеки T-Regx.
"/<div[^>]*><ul[^>]*>/"
preg_replace()
?