【问题标题】:Regular expression for matching a sequence?匹配序列的正则表达式?
【发布时间】:2014-08-13 08:56:06
【问题描述】:

我的文本包含已知模式中的短语,例如:#%some phrase%#,该短语可以是任何东西(显然它不会包含模式 '%#')。
现在,我想构建一个正则表达式(在 php 中),它将匹配 2 个或更多短语的序列(它们之间有或没有空格),所以如果,例如,我的文本是:

#%jjj jjj%#  kkjjkkjj kkjjkkjj  #%kkk kkk%# #%ttt mmm%#

我希望正则表达式匹配:

#%kkk kkk%# #%ttt mmm%#

我试过这个正则表达式:/(?:#%.+?(?!%#).%#\s*){2,}/

但由于某种奇怪的原因,它匹配整个字符串,并忽略了否定的前瞻。

此外,我的完整任务是匹配一系列短语,它们之间最多包含 1 个字符(除了空格)。

如何实现?

测试用例:

文字:

#%Prime target%# #%Online stuff%# English Deutsch Norsk Svenska Suomi English AU English CA #%Home%# #%About Us%# #%Fair Play%# #%Promotions%#

应该匹配:

  1. #%Prime target%# #%在线内容%#
  2. #%Home%# #%About Us%# #%Fair Play%# #%Promotions%#

文字:

#%Prime target%# 英语 Deutsch Norsk Svenska Suomi 英语 AU 英语 CA #%Home%# | #%关于我们%# | #%公平竞争%# | #%促销%#

应该匹配:

  1. #%首页%# | #%关于我们%# | #%公平竞争%# | #%促销%#

【问题讨论】:

  • 我写道“我的完整任务是匹配一系列短语,它们之间最多包含 1 个字符(除了空格)。”
  • 我根据您的测试输入更新了我的答案,看看是否有帮助

标签: php regex pcre


【解决方案1】:

你必须修改你的正则表达式:

(?:#%(?:(?!%#).)+?.%#\s*)(?:.?\s*#%(?:(?!%#).)+?.%#\s*)+

(?: ) 组的后视中包装.+? 捕获会强制惰性匹配在继续时不匹配(?!%#),这也是您原来的正则表达式不起作用的原因。

另外,将其克隆到一个单独的组中,匹配前缀为.?,以便在组之间可以接受字符。

这是regex demo

测试用例:

#%jjj jjj%# kkjjkkjj kkjjkkjj #%kkk kkk%# #%ttt mmm%#

匹配:
#%kkk kkk%# #%ttt mmm%#

【讨论】:

  • 它似乎有效!我将不得不用更复杂的文本对其进行测试,以确保......你能再次向我解释一下为什么这个修改会产生影响吗?我没有使用后视,而是负前瞻, (?: ) 只是一个非捕获组。
  • 问题是:在(?:#%.+?(?!%#).%#\s*){2,} 中,您的后视实际上毫无用处。 .+? 告诉引擎逐个字符地运行,直到它可以到达下一个序列 - (?!%#). 这意味着只要字符串的一部分以 #% 开头,而字符串的另一部分以 @987654333 开头@,您的旧正则表达式将从字符串中的第一个到最后一个 %# 匹配。这意味着,一切。我通过在 .+? 匹配上强制执行 (?!%#) 来解决这个问题。
【解决方案2】:

根据您的测试输入,我想出了这个正则表达式,简短且仍然有效

/((?:#%[^#]*%#(?:\s.\s|\s)){2,})/g

测试字符串

test 1

#%Prime target%# #%Online stuff%# English Deutsch Norsk Svenska Suomi English AU English CA #%Home%# #%About Us%# #%Fair Play%# #%Promotions%#

test 2

#%Prime target%# English Deutsch Norsk Svenska Suomi English AU English CA #%Home%# | #%About Us%# | #%Fair Play%# | #%Promotions%#

结果

  • 匹配 1
    1. [8-42]#%Prime target%# #%Online stuff%#
  • 比赛 2
    1. [100-151]#%Home%# #%About Us%# #%Fair Play%# #%Promotions%#
  • 第 3 场比赛
    1. [236-293]#%Home%# | #%About Us%# | #%Fair Play%# | #%Promotions%#

尝试演示here

【讨论】:

  • @pushpraj 我想你不理解我,我不想匹配每个短语,我想匹配整个序列(如果它包含超过 2 个带或不带空格的短语和它们之间可选 1 个字符)
  • 在这种情况下,只需将其修改为/(?<=\s|^)((#%[^#]*?%#)\s*.?\s*((?2)))/g,那么第一个捕获组就是您需要的try here
【解决方案3】:

我想你想要:

/(?:.*?#%.*?%#.*?)(#%.*%#)/g

它首先找到#%...%#(不贪心)然后匹配下一个#%...%#(贪心)

Demo

【讨论】:

  • 但它也匹配短语之间的任何内容,我只想匹配一个短语序列,如解释的那样,它们之间最多包含 1 个字符和空格。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 2013-12-30
  • 2018-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
相关资源
最近更新 更多