我有以下错误:


警告: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)) )); ?>


如何解决此问题?

评论

在模式周围添加定界符:“ /
] *>
    ] *> /”

    @mario我真的不明白你为什么在这里赏金吗?您是否真的在这里寻找新的答案?如果是,当前版本有什么问题?

    @ Rizier123赏金描述说明了一切:“一个或多个答案是模范,值得额外赏金。”

    是的,这并不意味着吸引更多答案。现有的例子已经很好。这是一个很好的视觉解释,很可能适用于许多类似的情况。此类迷你赏金主要旨在作为临时公共书签-使其更加知名。也许可以将其确立为另一个通用参考。 (尽管在事后制作带有附加示例和链接的人工CW答案很有意义……)

    @ Rizier123我将在7.5小时内将其选中。赏金奖励的有效期为24小时。以我的经验,无论如何,您都会在赏金期满时获得最多的意见。可能不会吸引新的答案(不需要;但又不想劝阻任何人)。这也是为什么我将CW答案保持在“隐藏模式”的原因。最后在pcre.c中解释定界符提取,然后再次取消删除它。同时,投票确实是主要答案。 CW实际上只是附录:]

#1 楼

为什么会发生错误

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

通常出现“未知修饰符X”错误在以下两种情况下会发生:



当正则表达式缺少分隔符时。


在模式中使用定界符而没有转义时。


在这种情况下,正则表达式为<div[^>]*><ul[^>]*>。正则表达式引擎将从<>的所有内容都视为正则表达式模式,并将其后的所有内容均视为修饰符。 ]定界符。这就是PHP引发该错误的原因。
根据模式,未知的修饰符抱怨也可能与>*+p/或几乎任何其他字母/符号有关。只有)是有效的PCRE修饰符。

如何修复

修复很容易。只需使用任何有效的定界符包装您的正则表达式模式即可。在这种情况下,您可以选择〜并获得以下内容:

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


如果使用分隔符时仍收到此错误,则可能是因为模式本身包含上述定界符的未转义出现。

或转义定界符

imsxeADSUXJu当然会引发错误。因此,如果正则表达式内的任何地方都出现\,则可以使用\反斜杠对其进行转义:

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


如果您的正则表达式模式包含很多定界符,则这是一项繁琐的工作字符。

当然,更干净的方法是完全使用其他定界符。理想情况下,这个字符不会出现在正则表达式模式中的任何地方,例如/foo[^/]+bar/i-#

更多阅读: //www.regular-expressions.info/php.html

如何在PHP中将ereg表达式转换为preg? (缺少定界符)

…中的未知修饰符'/'?它是什么? (使用#foo[^/]+bar#i时)


评论


我注意到,当其中一个分隔符位于preg_quote()中时,也会发生同样的情况,因此类似preg_replace('/'。preg_quote('/').'/ i','',$ string);。给出与主题相同的错误。斜线不应该被preg_quote()所转义吗?

– TechNyquist
16年4月29日在9:47

在将一些旧的ereg调用更新为preg_match时遇到了这个问题。必须引入定界符。

– JoshP
17年2月28日在16:04

#2 楼

其他示例

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




如果忘记添加正则表达式/分隔符/,则第一个非字母符号将被假定为一个。因此,警告通常是关于分组(…)[…]元符号之后的内容:

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的“全局”搜索子项。还:
·警告:preg_replace():未知修饰符'g'
·preg_replace:错误的正则表达式=='未知修饰符'?通常(或应该)使正则表达式更加高尚和可读。

这允许使用内联/g注释。 PHP在PCRE之上实现了正则表达式定界符。但是,它不会以任何特殊方式处理/x#注释中的文字分隔符可能变成错误:

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


(还值得注意的是,将#用作#分隔符可能是不可取的。)


将变量插值到正则表达式中需要对其进行转义,或者本身是有效的正则表达式。您无法事先告知这是否可行:

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


在这种情况下最好应用#

另请参见:< br··...中未知的修饰符“ /”?

另一种替代方法是对未加引号的文字字符串使用#abc+#x转义:

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


请注意,这只是meta的便捷快捷方式符号,不可靠/不安全。如果$var = preg_quote($var, "/")本身包含文字\Q…\E(但是不太可能),它将崩溃。而且它不会掩盖定界符本身。

不赞成使用的修饰符/ e是一个完全不同的问题。这与定界符无关,但是隐式表达式解释模式已被淘汰。另请参阅:用preg_replace_callback

替代正则表达式定界符

已弃用的preg_replace / e


如上所述,对此错误的最快解决方案是选择一个不同的定界符。可以使用任何非字母符号。视觉上独特的通常是首选:


$var
'\E'
~abc+~
!abc+!
@abc+@
#abc+#

从技术上讲,您可以使用=abc+=%abc+%作为分隔符。但是,最好避免使用本身用作正则表达式元字符的符号。

$abc$作为定界符也很流行。但是,应与|abc| / #可读性修饰符结合使用。然后您不能使用xPCRE_EXTENDED注释,因为它们会被混淆为定界符。与它们相对应的PHP字符串框:

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


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

配对定界符

配对定界符是一个有趣的变体。您可以使用任何# inline (?#…) " '括号/大括号组合来代替正则表达式的两端使用相同的符号。

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


它们中的大多数也可以用作正则表达式元字符,您通常可以不用再花功夫就可以使用它们。只要正则表达式中的那些特定花括号/括号正确配对或转义,这些变体就很容易阅读。

花式正则表达式分隔符

有点懒惰的技巧(这不是认可)正在使用不可打印的ASCII字符作为分隔符。通过在正则表达式字符串中使用双引号,并在定界符中使用八进制转义符,可以轻松地在PHP中使用它:

因此,它极不可能出现在大多数正则表达式模式中。即使不是很清晰,这也适合在这里使用。

遗憾的是,您不能使用Unicode字形<...>作为分隔符。 PHP仅允许单字节字符。为什么是这样?好吧,很高兴您问到:

PCRE上的PHP分隔符

(...)函数利用PCRE regex引擎,该引擎本身并不在乎或提供定界符。为了与Perl相似,[...]函数实现了它们。这也是为什么可以使用修饰符{...}而不是仅将常量用作参数的原因。
有关如何对正则表达式字符串进行预处理的信息,请参见ext / pcre / php_pcre.c:


首先所有前导空格都将被忽略。

任何非字母数字符号均被视为假定的定界符。请注意,PHP仅支持单字节字符:

 preg_match("
delimiter = *p++;
if (isalnum((int)*(unsigned char *)&delimiter) || delimiter == '\') {
        php_error_docref(NULL,E_WARNING, "Delimiter must not…");
        return NULL;
}
1 abc+
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++;
}
1mix"


regex字符串的其余部分从左到右遍历。仅反斜杠1-转义的符号被忽略。不遵守preg_*preg_*的转义。
如果再次找到分隔符,则验证其余部分仅包含修饰符。

如果分隔符是/ism可配对的花括号/括号之一,那么处理逻辑就更加精细。

q4312078q

它寻找正确配对的左右定界符,但是在计数时忽略其他花括号/括号类型。

仅在切掉分隔符和修饰符标志之后,原始正则表达式字符串才传递到PCRE后端。

现在这一切都无关紧要。但是说明了分隔符警告的来源。而且整个过程都必须具有最少的Perl兼容性。当然,有一些细微的偏差,例如\字符类上下文在PHP中未得到特殊处理。

更多参考资料


preg_match(); -PHP中的未知修饰符'+'
PHP中的未知修饰符'/'错误
PHP RegExpr错误当将preg_match()与REGEX表达式一起使用时,未知修饰符'('
未知修饰符'(' /> PHP:正则表达式-未知修饰符错误
警告:preg_match()[function.preg-match]:未知修饰符'('

preg_match()什么时候发生:未知修饰符错误?(只是一个写得很好的问题,它证明了先前的研究)



评论


很好的解释

– Svetoslav Marinov
17年9月13日在9:13

#3 楼

如果要获取异常(MalformedPatternException),而不是警告或使用preg_last_error(),请考虑使用T-Regx库:

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