it-roy-ru.com

Предупреждение: 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)) )); ?>

Как я могу решить эту проблему?

38
user3122995

Warum tritt der Fehler auf?

В PHP muss ein regulärer Ausdruck in ein Paar Trennzeichen eingeschlossen werden. Ein Trennzeichen kann ein believebiges nicht alphanumerisches Zeichen ohne Backslash and ohne Leerzeichen sein. /, #, ~ sind die am häufigsten verwendeten. Es ist zu beachten, dass es auch möglich ist, Begrenzer im Klammer-Stil zu verwenden, wenn die öffnenden und schließenden Klammern die sind Start-and Endbegrenzer sind, d. H. <pattern_goes_here>, [pattern_goes_here] usw. sind alle gültig.

Der Fehler " Неизвестный модификатор X" tritt normalerweise in den folgenden beiden Fällen auf:

  • Венн в Ihrem regulären Ausdruck Trennzeichen fehlen .

  • Венн Си дас Треннцзейхен Внутренняя песня Мустерс вербенден, ох эс цу масьерен .

В осеннем осеннем сезоне Ausdruck <div[^>]*><ul[^>]*>. Die Regex-Engine betlechtet alles von < bis > als das Regex-Muster und alles danach als Modifikatoren.

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

] ishier ein unbekannter Modifikator, da er nach dem schließenden Trennzeichen > angezeigt wird. Das ist der Grund, warum PHP diesen Fehler auslöst.

Je nach Muster handelte es sich bei der unbekannten Модификатор-Beschwerde möglicherweise auch um *, +, p, / oder ) oder fast jedenenen. Nur imsxeADSUXJu ist gültige PCRE-Modifikatoren .

Wie man es repariert

Die Lösung ist einfach. Wickeln Sie einfach Ihr Regex-Muster mit gültigen Trennzeichen ein. В осенний осенний день~и bekomme folgendes:

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

Вен Зи Дезен Фехлер эрхальтен, обьявление Сий Эйн Треннцайхен Вервендет Хабен, Канн Дайс Даран Лиген, Дасс Дас Мустер Селбст Нихт Умшлоссене Воркоммен умирает Треннзейхенс Энтхельт.

Од Энткоммен Бегренцер

/foo[^/]+bar/i würde sicherlich einen Fehler auslösen. Sie können es также с\Обратная косая черта, wenn es irgendwo innerhalb des regulären Ausdrucks erscheint:

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

Dies ist eine mühsame Aufgabe, wenn Ihr Regex-Muster so viele Vorkommen des Begrenzungszeichens enthält.

Der sauberere Weg wäre natürlich, ein anderes Trennzeichen zu verwenden. Im Idealfall ein Zeichen, das nirgendwo im Regex-Muster vorkommt, sagen Sie # - #foo[^/]+bar#i.

Lesen Sie weiter:

84
Amal Murali

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

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

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

    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| для разделителей. Однако лучше избегать символов, которые сами являются метасимволами регулярных выражений.

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

Разделители только для цитат

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

  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 допускает только однобайтовые символы. И почему так? Хорошо, рад, что вы спросили:

Разграничители PHP на PCRE

Функции preg_* используют механизм регулярных выражений PCRE , который сам не заботится о разделителях и не предоставляет их. Для сходства с Perl их реализуют функции 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;
    }
    
  • Остальная часть строки регулярного выражения проходит слева направо. Только обратная косая черта \\- экранированные символы игнорируются. \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.

Больше ссылок

14
mario

Если вы хотите получить исключение (InvalidPatternException) вместо предупреждений или использования preg_last_error() - рассмотрите возможность использования библиотека T-Regx :

<?php
try 
{
    return pattern('invalid] pattern')->match($s)->all();
}
catch (InvalidPatternException $e) 
{
    // your pattern was invalid
}
0
Danon