用星号替换不包括某些模式的所有单词边界

Replace all word boundaries excluding certain patterns with an asterisk

我正在使用 Full Text Index in boolean mode,但我需要替换所有单词边界(仅单词结尾)当单词

符合上述两种情况的模式是

(".+?"|[\w]+[*])

而单词边界只是 \b。问题是我无法创建正则表达式,我尝试使用排除模式,但我认为我使用它的方式不对

(?=\b)(?=(?!(".+?"|[\w]+[*])))

像这样

谢谢

为了解决这个问题我不得不使用:

  • 负向后看(?<!")排除前面有引号的词界
  • 否定前瞻(?!["*])(?!\s[\w]+["*])排除以*"
  • 结尾的词
  • 如果要select超过n-1个字符的单词,可以设置一个限制(?<=[\w]{4})
(?<!")(?<=\w)\b(?!\s[\w]+["*])(?!["*])
(?<!")(?<=[\w]{4})\b(?!\s[\w]+["*])(?!["*]) // Words with lenght >= 4

我假设您希望在长度至少为 4 且未以星号结尾且不在用双引号分隔的字符串内的每个单词的末尾添加一个星号。

假设您的字符串格式正确,双引号的数量是偶数,您可以将以下正则表达式匹配的捕获组 1 的内容替换为捕获内容附加的星号第 1 组:

(\w{4,})(?!\w|\*|[^"]*"(?:(?:[^"]*"{2}))*[^"]*$)

Demo

正则表达式可以分解如下

(\w{4,})          # match >= 4 word characters
(?!               # begin negative lookahead
  \w              # match a word character
|                 # or (alternation) 
  \*              # match '*'
|                 # or
  [^"]*"          # match >= 0 chars other than '"' then '"'
  (?:             # begin a non-capture group
    (?:[^"]*"){2} # match >= 0 chars other than '"' then '"' in
                  # a non-capture group
    {2}           # execute the above non-capture group twice
  )*              # end non-capture group
  [^"]*"          # match >= 0 chars other than '"' then '"'
  $               # match end of string
)                 # end negative lookahead

注意

[^"]*"(?:(?:[^"]*"{2}))*[^"]*$

断言当前字符串位置后面没有奇数个双引号(即当前字符串位置不在由双引号分隔的字符串内)。


另一种方法是使用正则表达式,它首先尝试匹配您不想要的内容(双引号字符串中的单词),如果失败则尝试将您想要的内容保存到捕获组中,支付不关注比赛,只关注捕获组:

"[^"]*"|(\w{4,})(?!\w|\*)

Demo

正如您在 link

看到的
Cats in "some very* stylish" hats

转换为

Cats* in * hats*

因为它显示 匹配 被转换为 $*,但是通过将替换限制为捕获组,我们得到了期望的结果:

Cats* in "some very* stylish" hats*

以编程方式将替换限制为捕获组,这当然取决于所使用的语言(问题中尚未确定)。例如,在 Ruby 中,可以这样写:

str = 'Cats in "some very* stylish" hats'
str.gsub(/"[^"]*"|(\w{4,})(?!\w|\/) { |s| s[0]=='"' ? s : +'*' }
  #=> "Cats* in \"some very* stylish\" hats*"

我给出的这两种方法是大多数正则表达式引擎都支持的。但是,还有其他方法可以利用有限数量的正则表达式引擎支持的功能。