0

我正在尝试创建一个正则表达式,它替换未被括号括起来的单词。

这是我目前拥有的:

$this->parsed = preg_replace('/\b(?<!\[)('.preg_quote($word).')\b/','[$1['.implode(",",array_unique($types)).']]',$this->parsed);

$word 可以是以下之一,“Burkely Mayfair Trunk”或“Trunk”。

它将替换句子

这个 Burkely Mayfair 树干很漂亮

为了

这个 [Burkely Mayfair [Trunk[productname]][productname]] 很不错

虽然应该变成

这个 [Burkely Mayfair Trunk[productname]] 很不错

由于它按照最大字符串到最小字符串的顺序进行替换,因此较小的字符串和/或单词部分的两次出现不应在字符串的已替换部分中替换。当它是字符串的第一部分时,它可以工作。

当我尝试进行动态后视时,它会出现以下错误:“编译失败:后视断言在偏移量 11 处不是固定长度”。我不知道如何解决这个问题。

任何人有任何想法?

4

2 回答 2

0

在玩了正则表达式的另一个早晨之后,我想出了一个非常肮脏的解决方案,它根本不灵活,但适用于我的用例。

$this->parsed = preg_replace('/\b(?!\[(|((\w+)(\s|\.))|((\w+)(\s|\.)(\w+)(\s|\.))))('.preg_quote($word).')(?!(((\s|\.)(\w+))|((\s|\.)(\w+)(\s|\.)(\w+))|)\[)\b/s','[$10['.implode(",",array_unique($types)).']]',$this->parsed);

它基本上所做的就是结合指定的关键字检查前面或后面没有单词、1 个单词或 2 个单词的括号。

不过,很高兴听到有人有更好的解决方案。

于 2013-09-10T09:56:46.547 回答
0

您可以将括号内的任何子字符串与\[[^][]*]模式匹配,然后使用(*SKIP)(*FAIL)PCRE 动词删除匹配项,并且仅在任何其他上下文中匹配您的模式:

\[[^][]*](*SKIP)(*FAIL)|your_pattern_here

请参阅正则表达式演示。要跳过配对嵌套方括号内的匹配项,请使用基于 recurssion 的正则表达式和子例程(注意它必须使用捕获组):

(?<skip>\[(?:[^][]++|(?&skip))*])(*SKIP)(*FAIL)|your_pattern_here

查看正则表达式演示

此外,由于您是动态构建模式,因此您需要preg_quote使用$word分隔符(此处为/)。

你的解决方案是

$this->parsed = preg_replace(
    '/\[[^][]*\[[^][]*]](*SKIP)(*FAIL)|\b(?:' . preg_quote($word, '/') . ')\b/', 
    '[$0[' . implode(",", array_unique($types)) . ']]',
    $this->parsed);

\[[^][]*\[[^][]*]]则表达式将匹配所有已用您的替换模式包装的出现:

  • \[- 一个[
  • [^][]*- 0+ 字符除了[]
  • \[- 一个[字符
  • [^][]*- 0+ 字符除了[]
  • ]]- 一个]]子串。
于 2020-05-24T11:23:56.340 回答