【问题标题】:Get all words that have not a specific prefix group获取所有没有特定前缀组的单词
【发布时间】:2017-09-23 15:56:42
【问题描述】:

我有一个如下形式的字符串

$string = "This is {test} for [a]{test2} for {test3}.";

我想得到所有没有方括号前缀的大括号。因此,在上面的字符串中,我想得到{test}{test3},而不是[a]{test2}

我在答案https://stackoverflow.com/a/977294/2311074 中发现,如果使用负前瞻,这可能是可能的。所以我尝试了

  $regex      = '/(?:(?!\[[^\}]+\])\{[^\}]+\})/';
  echo preg_match_all($regex, $string, $matches) . '<br>';
  print_r($matches);

但这仍然给了我所有三个大括号。

3

数组 ( [0] => 数组 ( [0] => {test} [1] => {test2} [2] => {test3} ) )

为什么这不起作用?

【问题讨论】:

  • @WiktorStribiżew 感谢您的详细回答。我正在赶上负面展望的话题。一旦我理解了你的答案,我会回复/投票。
  • 有什么不清楚的请马上问——我会在线几个小时。

标签: php regex


【解决方案1】:

如果您确定打开花括号之前只会有一对方括号(平衡),那么负向后看就可以了:

(?<!]){[^}]*}

Live demo

【讨论】:

  • 非常好的提示,谢谢:)! ]}不用转义吗?
【解决方案2】:

你的正则表达式失败的原因是它匹配任何{(后跟1+非}s,然后是}),如果它没有启动负前瞻内的模式序列,a [,除 } 之外的 1+ 个字符,然后是 ](这总是正确的,因此,您会得到所有 {...} 子字符串)。

使用(*SKIP)(*FAIL) technique:

\[[^]]*]\{[^}]+}(*SKIP)(*F)|\{[^\}]+}

请参阅regex demo

详情

  • \[[^]]*]\{[^}]+}(*SKIP)(*F) - 匹配
    • \[ - 一个[
    • [^]]* - 除] 之外的 0+ 个字符
    • ]\{ - ]{ 子字符串
    • [^}]+ - 除] 之外的 1+ 个字符
    • } - 文字 }
    • (*SKIP)(*F) - PCRE 动词丢弃到目前为止匹配的文本并强制引擎从当前位置继续寻找下一个匹配项(就像发生匹配一样)
  • | - 或
  • \{[^\}]+}:
    • \{ - 一个{
    • [^\}]+ - 除了}
    • 之外的 1+ 个字符
    • } - 文字 }

PHP demo

$string = "This is {test} for [a]{test2} for {test3}.";
$regex      = '/\[[^]]*]\{[^}]+}(*SKIP)(*F)|\{[^}]+}/';
echo preg_match_all($regex, $string, $matches) . "\n";
print_r($matches[0]);

输出:

2
Array
(
    [0] => {test}
    [1] => {test3}
)

【讨论】:

  • 谢谢。我刚刚意识到我的 rexgex 有一个错误,我实际上想使用 '/(?&lt;!\[[^\}]+\])\{[^\}]+\}/' 但这不起作用,因为 “lookbehind assertion MUST be fixed length” stackoverflow.com/questions/3796436/…。所以在这里使用你的跳过失败方法是有意义的,而不是倒退。谢谢!
  • 很高兴我能帮上忙。 (*SKIP)(*FAIL) 是唯一正确的方法来否定 PCRE 中的某些东西,而无需做出假设就无法访问负无限宽度。
猜你喜欢
  • 1970-01-01
  • 2011-02-22
  • 2017-11-07
  • 2013-08-31
  • 1970-01-01
  • 1970-01-01
  • 2014-01-12
  • 2021-06-13
  • 1970-01-01
相关资源
最近更新 更多