简而言之
[...] 中的任何零宽度断言都失去了零宽度断言的含义。 [\b] 不匹配单词边界(它匹配退格,或者,在 POSIX 中,\ 或 b),[$] 匹配文字 $ 字符,[^] 要么是错误,要么,如在 ECMAScript 正则表达式风格中,任何字符。与\z、\Z、\A 锚点相同。
您可以使用以下任何一种模式来解决问题:
[&?]list=([^&]*)
[&?]list=(.*?)(?=&|$)
[&?]list=(.*?)(?![^&])
如果您需要检查“绝对”、明确的字符串结束锚点,您需要记住这是各种正则表达式风格,它用不同的结构表示:
[&?]list=(.*?)(?=&|$) - OK for ECMA regex (JavaScript, default C++ `std::regex`)
[&?]list=(.*?)(?=&|\z) - OK for .NET, Go, Onigmo (Ruby), Perl, PCRE (PHP, base R), Boost, ICU (R `stringr`), Java/Andorid
[&?]list=(.*?)(?=&|\Z) - OK for Python
字符序列与单个字符或字符串结尾之间的匹配(当前场景)
.*?([YOUR_SINGLE_CHAR_DELIMITER(S)]|$) 模式 (suggested by João Silva) 效率相当低,因为正则表达式引擎首先检查出现在惰性点模式右侧的模式,并且只有当它们不匹配时才会“扩展”惰性点状图案。
在这些情况下,建议使用negated character class(或 POSIX 谈话中的 括号表达式):
[&?]list=([^&]*)
See demo。 详情
-
[&?] - 匹配 & 或 ? 的正字符类(注意字符类中字符/字符范围之间的关系是 OR 关系)
-
list= - 子字符串,字符序列
-
([^&]*) - 捕获组 #1:除 & ([^&]) 之外的零个或多个 (*) 字符,尽可能多
检查尾随单个字符分隔符是否存在而不返回它或字符串结尾
大多数正则表达式风格(包括从 ECMAScript 2018 开始的 JavaScript)支持环视,即仅在模式匹配或不匹配时才返回 true 或 false 的构造。它们在预期可能以相同字符开头和结尾的连续匹配时至关重要(参见原始模式,它可能匹配以& 开头和结尾的字符串)。虽然不希望出现在查询字符串中,但这是一种常见情况。
在这种情况下,您可以使用两种方法:
- 具有包含正字符类的交替的正前瞻:
(?=[SINGLE_CHAR_DELIMITER(S)]|$)
- 只有负字符类的负前瞻:
(?![^SINGLE_CHAR_DELIMITER(S)])
负前瞻解决方案效率更高一些,因为它不包含增加匹配过程复杂性的交替组。 OP 解决方案看起来像
[&?]list=(.*?)(?=&|$)
或
[&?]list=(.*?)(?![^&])
请参阅 this regex demo 和 another one here。
当然,如果尾随定界符是多字符序列,则只有正向超前解决方案才有效,因为[^yes] 不会否定字符序列,但类中的字符(即[^yes] 匹配除@987654355 之外的任何字符@、e 和 s)。