警告:preg_replace():未知修饰符
Posted
技术标签:
【中文标题】警告:preg_replace():未知修饰符【英文标题】:Warning: preg_replace(): Unknown modifier 【发布时间】:2014-01-09 10:05:43 【问题描述】:我有以下错误:
警告:preg_replace(): Unknown modifier ']' in xxx.php on line 38
这是第 38 行的代码:
<?php echo str_replace("</ul></div>", "", preg_replace("<div[^>]*><ul[^>]*>", "", wp_nav_menu(array('theme_location' => 'nav', 'echo' => false)) )); ?>
我该如何解决这个问题?
【问题讨论】:
在图案周围添加分隔符:"/<div[^>]*><ul[^>]*>/"
@mario 我真的不明白你为什么在这里放赏金?你真的在这里寻找新的答案吗?如果是的话,当前的有什么问题?
@Rizier123 赏金说明说明了一切:“一个或多个答案具有示范意义,值得额外赏金。”
是的,这并不是为了吸引更多答案。现有的已经是一个非常好的例子。这是一个很好的视觉解释,可能适用于许多类似的情况。此类迷你赏金主要用作临时公共书签 - 使其更广为人知。也许将其确立为另一个普遍的参考。 (虽然用额外的例子 + 链接来制作一个人工的 CW 答案可能是有意义的……)
@Rizier123 我会在 7.5 小时内打勾。赏金奖励在之后的 24 小时内有效。以我的经验,无论如何,在赏金期结束时,您会获得最多的观看次数。可能不会吸引新的答案(不需要;但仍然不想劝阻任何人)。这也是我将 CW 答案保持在“潜行模式”的原因。最后解释一下pcre.c
中的分隔符提取,然后再次取消删除它。与此同时,投票确实属于主要答案。 CW 真的只是附录:]
【参考方案1】:
为什么会出现错误
在 PHP 中,正则表达式需要包含在一对 delimiters 中。分隔符可以是任何非字母数字、非反斜杠、非空白字符; /
、#
、~
是最常用的。请注意,也可以使用括号样式的分隔符,其中开始和结束括号是开始和结束分隔符,即<pattern_goes_here>
、[pattern_goes_here]
等都有效。
“未知修饰符X”错误通常出现在以下两种情况:
当您的正则表达式缺少分隔符时。
当您使用分隔符在模式中不转义它。
在这种情况下,正则表达式是<div[^>]*><ul[^>]*>
。正则表达式引擎将从<
到>
的所有内容视为正则表达式模式,然后将所有内容视为修饰符。
Regex: <div[^> ]*><ul[^>]*>
│ │ │ │
└──┬──┘ └────┬─────┘
pattern modifiers
]
这里是一个未知修饰符,因为它出现在>
分隔符之后。这就是 PHP 抛出该错误的原因。
根据模式,未知修饰符投诉可能是关于 *
、+
、p
、/
或 )
或几乎任何其他字母/符号。只有imsxeADSUXJu
是valid PCRE modifiers。
如何解决
修复很简单。只需使用任何有效的分隔符包装您的正则表达式模式。在这种情况下,您可以选择 ~ 并获得以下信息:
~<div[^>]*><ul[^>]*>~
│ │
│ └─ ending delimiter
└───────────────────── starting delimiter
如果您在使用分隔符后仍收到此错误,则可能是因为模式本身包含未转义的所述分隔符。
或转义分隔符
/foo[^/]+bar/i
肯定会抛出错误。因此,如果它出现在正则表达式中的任何位置,您可以使用 \ 反斜杠对其进行转义:
/foo[^\/]+bar/i
│ │ │
└──────┼─────┴─ actual delimiters
└─────── escaped slash(/) character
如果您的正则表达式模式包含如此多的分隔符,这将是一项乏味的工作。
当然,更简洁的方法是完全使用不同的分隔符。理想情况下,该字符不会出现在正则表达式模式中的任何位置,例如 #
- #foo[^/]+bar#i
。
更多阅读:
PHP regex delimiters http://www.regular-expressions.info/php.html How can I convert ereg expressions to preg in PHP?(缺少分隔符) Unknown modifier '/' in …? what is it?(关于使用preg_quote()
)
【讨论】:
我注意到当分隔符之一位于preg_quote()
内时也会发生同样的情况,因此preg_replace('/'.preg_quote('/').'/i','',$string);
之类的内容会给出相同的主题错误。斜线不应该被preg_quote()
转义吗?
我在将一些旧的ereg
调用更新为preg_match
时遇到了这个问题。不得不引入分隔符。【参考方案2】:
其他示例
reference answer 已经解释了“未知修饰符”警告的原因。这只是其他典型变体的比较。
当忘记添加正则表达式/
delimiters/
时,第一个非字母符号将被假定为一个。因此,警告通常是关于分组 (…)
、[…]
元符号后面的内容:
preg_match("[a-zA-Z]+:\s*.$"
↑ ↑⬆
有时您的正则表达式已经使用了自定义分隔符(此处为:
),但仍包含与未转义文字相同的字符。然后它被误认为是过早的分隔符。这就是为什么下一个符号会获得“未知修饰符❌”奖杯的原因:
preg_match(":\[[\d:/]+\]:"
↑ ⬆ ↑
使用经典的/
分隔符时,请注意不要将其包含在正则表达式中。尝试匹配 unescaped filenames 时最常发生这种情况:
preg_match("/pathname/filename/i"
↑ ⬆ ↑
或者当匹配尖括号/方括号样式tags:
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
标志。
另见: · Warning: preg_replace(): Unknown modifier 'g' ·preg_replace: bad regex == 'Unknown Modifier'?
一个更特殊的情况与 PCRE_EXTENDED /x
标志有关。这通常(或应该)用于使正则表达式更加崇高和可读。
这允许使用内联#
cmets。 PHP 在 PCRE 上实现了正则表达式分隔符。但它不会以任何特殊方式对待#
。这就是#
注释中的文字分隔符会变成错误的原因:
preg_match("/
ab?c+ # Comment with / slash in between
/x"
(还值得注意的是,使用#
作为#abc+#x
分隔符可能是双重不可取的。)
将变量插入正则表达式需要预先转义它们,或者它们本身是有效的正则表达式。您无法事先判断这是否可行:
preg_match("/id=$var;/"
↑ ↺ ↑
这种情况最好申请$var = preg_quote($var, "/")
。
另见: ·Unknown modifier '/' in ...? what is it?
另一种选择是使用 \Q…\E
转义符来处理不带引号的文字字符串:
preg_match("/id=\Q$var\E;/mix");
请注意,这只是元符号的便捷快捷方式,并不可靠/安全。如果$var
本身包含文字'\E'
(尽管不太可能),它就会崩溃。它本身就是not mask the delimiter。
不推荐使用的修饰符 /e 是一个完全不同的问题。这与分隔符无关,而是隐式表达式解释模式被逐步淘汰。另见:Replace deprecated preg_replace /e with preg_replace_callback
替代正则表达式分隔符
如前所述,解决此错误的最快方法是选择一个不同的分隔符。可以使用任何非字母符号。视觉上与众不同的通常是首选:
~abc+~
!abc+!
@abc+@
#abc+#
=abc+=
%abc+%
从技术上讲,您可以使用$abc$
或|abc|
作为分隔符。但是,最好避免符号本身充当正则表达式元字符。
哈希#
作为分隔符也很受欢迎。但应注意与x
/PCRE_EXTENDED
可读性修饰符结合使用。你不能使用# inline
或(?#…)
cmets,因为它们会被混淆为分隔符。
仅引用分隔符
偶尔您会看到 "
和 '
用作正则表达式分隔符,它们的对应部分用作 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
只是一个通常不需要的控制字符 ␁。因此,它极不可能出现在大多数正则表达式模式中。这使它适合这里,即使不是很清晰。
遗憾的是,您不能使用 Unicode glyps ❚
作为分隔符。 PHP 只允许单字节字符。那为什么呢?好吧,很高兴你问:
PCRE 顶部的 PHP 分隔符
preg_*
函数使用PCRE 正则表达式引擎,它本身并不关心或提供分隔符。为了与 Perl 相似,preg_*
函数实现了它们。这也是为什么您可以使用modifier letters /ism
而不仅仅是constants as parameter。
请参阅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;
正则表达式字符串的其余部分从左到右遍历。只有反斜杠\\
-转义符号被忽略。 \Q
and \E
escaping 不受尊重。
如果再次找到分隔符,则验证其余部分仅包含修饰符。
如果分隔符是([< )]> )]>
可配对的大括号/方括号之一,则处理逻辑更加复杂。
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 中没有得到特殊处理。
更多参考
preg_match(); - Unknown modifier '+' Unknown modifier '/' error in PHP PHP RegExpr error Unkown modifier '(' Unknown modifier '(' when using preg_match() with a REGEX expression PHP: Regex - Unknown modifier error Warning: preg_match() [function.preg-match]: Unknown modifier '(' When does preg_match(): Unknown modifier error occur?(只是一个写得很好的问题,展示了先前的研究)【讨论】:
很好的解释【参考方案3】:如果您想获得异常 (MalformedPatternException
),而不是警告或使用 preg_last_error()
- 考虑使用 T-Regx library:
<?php
try
return pattern('invalid] pattern')->match($s)->all();
catch (MalformedPatternException $e)
// your pattern was invalid
【讨论】:
以上是关于警告:preg_replace():未知修饰符的主要内容,如果未能解决你的问题,请参考以下文章
我在字符串上有几个 preg_replace 未知修饰符警告,但我不知道正则表达式修复 [重复]