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

我有以下错误:

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

这是第38行的代码:

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

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

为什么发生错误

在PHP中,正则expression式需要包含在一对分隔符中 。 分隔符可以是任何非字母数字,非反斜杠,非空白字符; /#~是最常用的。 请注意,也可以使用括号格式分隔符,其中开始和结束括号是开始和结束分隔符,即<pattern_goes_here>[pattern_goes_here]等都是有效的。

Unknown modifier X ”错误通常发生在以下两种情况下:

  • 当你的正则expression式缺less分隔符

  • 当您在图案使用分隔符 而不逃脱它。

在这种情况下,正则expression式是<div[^>]*><ul[^>]*> 。 正则expression式引擎将从<>所有内容视为正则expression式模式,之后将所有内容视为修饰符。

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

]这是一个未知的修饰符,因为它在closures>分隔符后出现。 这就是为什么PHP抛出这个错误。

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

如何解决它

修复很简单。 只要用任何有效的分隔符包装你的正则expression式模式。 在这种情况下,您可以select并获得以下内容:

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

如果尽pipe使用了分隔符,仍然收到此错误,可能是因为该模式本身包含所述分隔符的非转义事件。

或逃生分隔符

/foo[^/]+bar/i肯定会抛出一个错误。 所以如果它出现在正则expression式中的任何地方,你可以使用\ backslash来转义它:

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

如果你的正则expression式模式中包含了这么多的分隔字符,这是一个单调乏味的工作。

更干净的方法当然是完全使用不同的分隔符。 理想情况下,一个字符不会出现在正则expression式模式中,例如##foo[^/]+bar#i

更多阅读:

  • PHP的正则expression式分隔符
  • http://www.regular-expressions.info/php.html
  • 如何将eregexpression式转换为PHP中的preg? (缺less分隔符)
  • 未知的修饰符'/'在…? 它是什么? (使用preg_quote()

其他例子

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

  • 当忘记添加正则expression式/分隔符/ ,第一个非字母符号将被假定为一个。 因此,警告常常是关于分组(…) ,元符号后面的内容:

     preg_match("[a-zA-Z]+:\s*.$" ↑ ↑⬆ 
  • 有时你的正则expression式已经使用了一个自定义分隔符( :这里),但仍然包含与未转义文字相同的字符。 这被误认为是过早的分隔符。 这就是为什么下一个符号收到“未知修饰符”奖杯:

     preg_match(":\[[\d:/]+\]:" ↑ ⬆ ↑ 
  • 使用经典/分隔符时,请注意不要在正则expression式中使用它。 尝试匹配未转义的文件名时最常发生这种情况:

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

    或者当匹配angular度/方括号风格的标签 :

     preg_match("/<%tmpl:id>(.*)</%tmpl:id>/Ui" ↑ ⬆ ↑ 
  • 模板式(Smarty或BBCode)正则expression式模式通常需要{…}或括号。 两者通常应该逃脱。 (最外面的{}对是例外)。

    当没有使用实际的分隔时,它们也被误解为成对的分隔符。 如果他们也被用作文字字符,那当然是一个错误。

     preg_match("{bold[^}]+}" ↑ ⬆ ↑ 
  • 每当警告说“ 分隔符不能是字母数字或反斜杠 ”,那么你也完全忘记了分隔符:

     preg_match("ab?c*" ↑ 
  • unkown修饰符”g“ ”通常表示从JavaScript或Perl逐字拷贝的正则expression式。

     preg_match("/abc+/g" ⬆ 

    PHP不使用/g全局标志。 相反, preg_replace函数适用于所有的事件, preg_match_allpreg_match_all的“全局”search。

    所以,只要删除/g标志。

    也可以看看:
    · 警告:preg_replace():未知修饰符“g”
    · preg_replace:坏正则expression式=='未知的修饰符'?

  • 一个更奇怪的情况属于PCRE_EXTENDED /x标志 。 这经常(或应该)用于使正则expression式更高明和可读。

    这允许使用内嵌#评论。 PHP在PCRE上实现了正则expression式分隔符。 但它不会以任何特殊的方式处理# 这是如何在#注释中的文字分隔符可以成为一个错误:

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

    (另外值得注意的是,使用# as #abc+#x分隔符可以是不可取的。)

  • 插入variables到正则expression式需要它们被预先转义,或者是有效的正则expression式本身。 事先不知道这是否会奏效:

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

    在这种情况下最好应用$var = preg_quote($var, "/")

    也可以看看:
    ·…中的未知修饰符“/”? 它是什么?

    另一种select是使用\Q…\E转义为未加引号的文字string:

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

    请注意,这只是一个方便的捷径,不可靠/安全。 如果$var包含一个字面上的'\E'本身(不太可能),它就会崩溃。

  • 弃用的修饰符/ e是一个完全不同的问题。 这与分隔符无关,但隐含的expression式解释模式正在被逐步淘汰。 另请参阅: 用preg_replace_callbackreplace弃用的preg_replace / e

可选的正则expression式分隔符

正如已经提到的,解决这个错误最快的办法就是select一个明确的分隔符。 任何非字母符号都可以使用。 视觉上有特色的往往是首选的:

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

技术上你可以使用$abc$|abc| 为分隔符。 但是,最好避免使用符号作为正则expression式元字符。

散列#作为分隔符也相当stream行。 但是应该注意与x / PCRE_EXTENDED可读性修饰符结合使用。 您不能使用# inline(?#…)注释,因为这些会被混淆为分隔符。

仅引用分隔符

偶尔你会看到"'作为正则expression式分隔符与它们的conterpart配对作为PHPstringshell:

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

就PHP而言,这是完全有效的。 这有时是方便和不显眼的,但在IDE和编辑中并不总是清晰的。

配对分隔符

一个有趣的变化是配对分隔符。 而不是在正则expression式的两端使用相同的符号,你可以使用任何<...> (...) [...]括号/大括号的组合。

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

虽然他们大多数也可以作为正则expression元字符,你可以经常使用他们没有进一步的努力。 只要正则expression式中的那些特定的大括号/ parens正确地配对或转义,这些变体是相当可读的。

花式正则expression式分隔符

一个有点懒惰的技巧(这是不赞成在此)使用不可打印的ASCII字符作为分隔符。 这很容易在PHP中使用正则expression式string的双引号和分隔符的八进制转义:

  preg_match("\001 abc+ \001mix" 

\001只是一个控制angular色,通常不需要。 因此,在大多数正则expression式模式中出现的可能性很小。 这使得它适合在这里,即使不是很清楚。

可悲的是,你不能使用Unicode glyps❚作为分隔符。 PHP只允许单字节字符。 为什么是这样? 那么,很高兴你问:

PCRE上的PHP分隔符

preg_*函数使用PCRE正则expression式引擎,它本身不关心或提供分隔符。 与Perl类似, preg_*函数实现它们。 这也是为什么你可以使用修饰符字母/ism而不是常量作为参数 。

请参阅ext / pcre / php_pcre.c关于正则expression式string是如何预处理的:

  • 首先,所有领先的空白都被忽略。

  • 任何非字母数字符号被视为推定的分隔符。 请注意,PHP只支持单字节字符:

     delimiter = *p++; if (isalnum((int)*(unsigned char *)&delimiter) || delimiter == '\\') { php_error_docref(NULL,E_WARNING, "Delimiter must not…"); return NULL; } 
  • 正则expression式string的其余部分从左到右遍历。 只有反斜杠\\转义的符号被忽略。

  • 如果再次find分隔符,其余部分将被validation为只包含修饰符字母。

  • 如果分隔符是([{< )]}> )]}>可配对括号/括号之一,则处理逻辑更加精细。

     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++; } 

    它会查找正确配对的左右分隔符,但在计算时会忽略其他大括号/括号types。

  • 原始正则expression式string只有在分隔符和修饰符标志被剪切后才传递给PCRE后端。

现在这一切都是不相关的。 但解释了分隔符警告的来源。 而这整个过程都具有最小的Perl兼容性。 当然还有一些小的偏差,比如在PHP中没有受到特殊处理的字符类上下文。

更多参考

  • 的preg_match(); – 未知修饰符“+”
  • PHP中的未知修饰符“/”错误
  • PHP RegExpr错误Unkown修饰符'('
  • 使用preg_match()和REGEXexpression式时,未知修饰符'('')
  • PHP:正则expression式 – 未知修饰符错误
  • 警告:preg_match()[function.preg-match]:未知修饰符'('
  • preg_match():什么时候会发生未知的修饰符错误?
    (只是一个精心编写的问题,展示了先前的研究)
Interesting Posts