警告:preg_replace():未知的修饰符']'

use*_*995 43 php regex wordpress preg-replace

我有以下错误:

警告:preg_replace():第38行的xxx.php中的未知修饰符']'

这是第38行的代码:

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

有人可以帮我解决这个问题吗?

Ama*_*ali 91

为什么会发生错误

在PHP中,正则表达式需要包含在一对分隔符中.分隔符可以是任何非字母数字,非反斜杠,非空白字符; /,#,~是最常用的.需要注意的是,还可以使用支架风格分隔符在打开和关闭括号开始和结束的分隔符,即<pattern_goes_here>,[pattern_goes_here]等等都是有效的.

" 未知修饰符X "错误通常发生在以下两种情况中:

  • 当您的正则表达式缺少分隔符时.

  • 在模式中使用分隔符而不转义它时.

在这种情况下,正则表达式是<div[^>]*><ul[^>]*>.正则表达式引擎从认为一切<>的正则表达式模式,以及后来的一切作为修饰.

Regex: <div[^>  ]*><ul[^>]*>
       ?     ?  ?          ?
       ???????  ????????????
       pattern    modifiers
Run Code Online (Sandbox Code Playgroud)

]这是一个未知的修饰符,因为它出现在结束>分隔符之后.这就是PHP抛出该错误的原因.

根据不同的模式,未知的修饰投诉可能也已经约*,+,p,/)或几乎任何其他字母/符号.只有imsxeADSUXJu有效PCRE修饰符.

如何解决它

修复很容易.只需使用任何有效的分隔符包装您的正则表达式模式.在这种情况下,您可以选择~并获取以下内容:

~<div[^>]*><ul[^>]*>~
?                   ?
?                   ?? ending delimiter
?????????????????????? starting delimiter
Run Code Online (Sandbox Code Playgroud)

如果您在使用分隔符时收到此错误,则可能是因为模式本身包含所述分隔符的未转义的出现.

或逃避分隔符

/foo[^/]+bar/i肯定会抛出错误.因此,\如果它出现在正则表达式中的任何位置,您可以使用反斜杠转义它:

/foo[^\/]+bar/i
?      ?     ?
??????????????? actual delimiters
       ???????? escaped slash(/) character
Run Code Online (Sandbox Code Playgroud)

如果您的正则表达式模式包含如此多的分隔符字符,则这是一项繁琐的工作.

当然,更简洁的方法是使用不同的分隔符.理想情况下,一个字符不会出现在正则表达式模式中的任何位置,比如说#- #foo[^/]+bar#i.

更多阅读:


mar*_*rio 14

其他例子

参考答案已经解释了"未知的修饰词"警告的原因.这只是其他典型变体的比较.

替代正则表达式分隔符

如前所述,这个错误的最快解决方案就是选择一个明确的分隔符.可以使用任何非字母符号.视觉上与众不同通常是首选的:

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

从技术上讲,你可以使用$abc$|abc|用于分隔符.但是,最好避免使用充当正则表达式元字符的符号.

散列#作为分隔符也很受欢迎.但应注意与x/ PCRE_EXTENDEDreadability修饰符结合使用.你不能使用# inline(?#…)评论,因为那些会被混淆为分隔符.

仅限报价的分隔符

偶尔你会看到"'使用正则表达式分隔符与它们的conterpart配对作为PHP字符串封装:

  preg_match("'abc+'"
  preg_match('"abc+"'
Run Code Online (Sandbox Code Playgroud)

就PHP而言,这是完全有效的.它有时方便且不引人注目,但在IDE和编辑器中并不总是清晰可辨.

配对分隔符

一个有趣的变体是成对分隔符.您可以使用任何<...> (...) [...] {...}括号/大括号组合,而不是在正则表达式的两端使用相同的符号.

  preg_match("(abc+)"   # just delimiters here, not a capture group
Run Code Online (Sandbox Code Playgroud)

虽然它们中的大多数也充当正则表达式元字符,但您可以经常使用它们而无需进一步努力.只要正则表达式中的那些特定括号/ parens正确配对或转义,这些变体就非常易读.

花哨的正则表达式分隔符

一个有点懒惰的技巧(此处未予以认可)使用不可打印的ASCII字符作为分隔符.通过使用正则表达式字符串的双引号和分隔符的八进制转义,这在PHP中很容易使用:

 preg_match("\001 abc+ \001mix"
Run Code Online (Sandbox Code Playgroud)

\001只是一个通常不需要的控制角色.因此,它几乎不可能出现在大多数正则表达式模式中.这使它适合这里,即使不是很清晰.

遗憾的是,您无法使用Unicode glyps ?作为分隔符.PHP只允许单字节字符.那为什么呢?嗯,很高兴你问:

PCRE上的PHP分隔符

这些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;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 正则表达式字符串的其余部分从左到右遍历.仅\\忽略反斜杠 - 已跳过的符号.\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++;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    它查找正确配对的左右分隔符,但在计数时忽略其他大括号/括号类型.

  • 只有在分隔符和修饰符标志被删除后,才会将原始正则表达式字符串传递给PCRE后端.

现在这有点无关紧要了.但解释了分隔符警告的来源.这整个过程都是至少具有Perl兼容性.当然有一些小的偏差,比如[…]没有在PHP中接受特殊处理的字符类上下文.

更多参考


归档时间:

查看次数:

33031 次

最近记录:

5 年,10 月 前