我需要找到“test”一词后面跟着“follow”,而中间没有另一个“test”。
示例:
test
word
word
word
test
test
word
word
follow
word
word
test
我只想要这个:
test
word
word
word
test
**test**
**word**
**word**
**follow**
word
word
test
虽然我对正则表达式不熟悉。任何建议都会很棒。
修改 虽然单词test会在那里多次出现,但单词follow只会出现在字符串中一次。
答案 0 :(得分:2)
你需要你的正则表达式在这里使用lookahead。
test(?:\w|\s(?!test))+?follow
(?:)
是一个非捕获组。 \w
匹配任何字符[a-zA-Z0-9_]
。 \s
匹配任何空格(包括新行)。 \s(?!test)
仅匹配未跟test
的换行符(在正则表达式用法中称为否定前瞻)。 ()+?
只会使比赛变得非贪婪。
使用匹配项测试输入:
test
word
**test**
**word**
**follow**
word
test
**test**
**word**
**word**
**follow**
word
word
**test**
**word**
**follow**
<小时/> 以下正则表达式也消除了任何子字符串匹配(如测试中的测试,抗议等)。
(?<!\w)(test)\s(?!\1\s)(?:\w|\s(?!\1\s))*?(?<!\w)follow(?!\w)
答案 1 :(得分:1)
为了简单起见,我个人不会在这里使用正则表达式:
text = (
"""test
word
word
word
test
test
word
word
follow
word
word
test
"""
)
def find_patterns(text):
curr = []
for word in text.split('\n'):
if word == 'test':
curr = ['word'] # start found sequence (also resets an existing one)
else:
if curr: # if a sequence has been started by 'test'
curr.append(word) # otherwise just add to current sequence
if word == 'follow': # end of sequence
yield curr # yield one result
curr = [] # reset sequence
print list(find_patterns(text))
输出:
[['test', 'word', 'word', 'follow']]
答案 2 :(得分:0)
在某些情况下,Ravi的正则表达式会产生错误的结果 例如:
import re
s = """test
word 1
word 2
word 3
test
tutulululalalo
testimony
word A
word B
follow
word X
word Y
test
"""
pat = ('test(?:\w|\s(?!test))+?follow')
print re.findall(pat,s)
#
#result : ['testimony\nword A\nword B\nfollow']
模式必须是:
pat = ('test(?=\s)' '(?:\w|\s(?!test(?=\s)))+?' 'follow')
print re.findall(pat,s)
#
#result : ['test \ntutulululalalo\ntestimony\nword A\nword B\nfollow']
此外,我没有看到OR表达的兴趣。这有效:
pat = ('(test(?=\s)' '(?:.(?!test(?=\s)))+?' 'follow)')
print re.findall(pat,s,re.DOTALL)
#
#result : ['test \ntutulululalalo\ntestimony\nword A\nword B\nfollow']
最后,我更喜欢以下模式,因为它只通过一次验证开始'test'和结束'follow'之间没有'test',
'(?:\w|\s(?!test(?=\s)))+?'
和'(?:.(?!test(?=\s)))+?'
验证每个字符是否跟随'follow':
pat = ('test(?=\s)'
'(?!.+?test(?=\s).*?follow)'
'.+?'
'follow')
print re.findall(pat,s,re.DOTALL)
#
#result : ['test \ntutulululalalo\ntestimony\nword A\nword B\nfollow']
正如Ravi Thapliyal指出的那样,我的最后一个正则表达式
pat = ('test(?=\s)'
'(?!.+?test(?=\s).*?follow)'
'.+?'
'follow')
也不完美。
我尝试过这种模式,因为我从不喜欢模式(?!.(?=something))+
我的上一个正则表达式模式应该取代这个不受欢迎的模式
嗯,它不起作用,我努力使它工作没有成功,虽然在我看来,曾经有一段时间我使用这种模式与微妙的附加部分,使其工作。
唉,我没有成功,我想我会放弃它可能会在某一天工作的想法
因此,我决心放弃我的古老想法,并且明确地认为我从未喜欢的模式是最明显,可理解和依旧的模式。
现在我有第二个错误承认:我发现Ravi Thapliyal的正则表达式在某些情况下不起作用,但我没有想到所有可能的失败案例。
但是它很容易纠正;我不应该只用一个先行断言来编写test(?=\s)
,而应该使用lookbehind和lookahead断言编写(?<=\s)test(?=\s)
。
Ravi Thapliyal选择写(?<!\w)(test)\s(?!\1\s)
,但这篇文章有一些缺点:
- 必须(?!\\1\s)
而不是(?!\1\s)
- 它要求在捕获组中定义(test)
,然后整个匹配不能简单地列在re.findall()
列表中或使用re.finditer()
生成器生成
他还写了(?:\w|\s(?!\\1\s))*?
。我没有看到将模式(?!.(?=something))+
与OR表达式复杂化的兴趣,而使用点可以做同样的工作。
另外,对我来说,最默认的一点是Ravi的正则表达式模式在包含其他字符的字符串中不能与用\w
由于所有这些原因,我提出以下纠正的解决方案:
import re
s1 = """test
word 1
word 2
test
word 3
tutulululalalo
protest
testimony
word
unfollow
word B
follow
word X
test
word Y
follow
"""
s2 = """test
word 1
word 2
test
word 3
tutulululalalo
protest
testimony
word ???????
unfollow
word B
follow
word X
test
word Y
follow
"""
# eyquem's pattern
fu = '(?<=\s)%s(?=\s)'
a = fu % 'test'
z = fu % 'follow'
pat = ('%s'
'(?:(?!%s).)+?'
'%s'
% (a,a,z))
# Ravi's pattern
patRT = ('(?<!\w)(test)\s'
'(?:\w|\s(?!\\1\s))*?(?<!\w)follow(?!\w)')
for x in (s1,s2):
print x
print re.findall(pat,x,re.DOTALL)
print
print [m.group() for m in re.finditer(patRT,x)]
print
结果
test
word 1
word 2
test
word 3
tutulululalalo
protest
testimony
word
unfollow
word B
follow
word X
test
word Y
follow
['test\nword 3\ntutulululalalo\nprotest\ntestimony\nword\nunfollow\nword B\nfollow', 'test\nword Y\nfollow']
['test\nword 3\ntutulululalalo\nprotest\ntestimony\nword\nunfollow\nword B\nfollow', 'test\nword Y\nfollow']
test
word 1
word 2
test
word 3
tutulululalalo
protest
testimony
word ???????
unfollow
word B
follow
word X
test
word Y
follow
['test\nword 3\ntutulululalalo\nprotest\ntestimony\nword ???????\nunfollow\nword B\nfollow', 'test\nword Y\nfollow']
['test\nword Y\nfollow'
准确回答问题:
s = """test
word 1
word 2
test
word 3
tutulululalalo
protest
testimony
word ???????
unfollow
word B
follow
word X
test
word Y
follow
"""
fu = '(?<=\s)%s(?=\s)'
a,z = fu % 'test' , fu % 'follow'
pat = ('%s'
'(?:(?!%s).)+?'
'%s'
% (a,a,z))
def ripl(m):
return re.sub('(?m)^(.*)$','**\\1**',m.group())
print re.sub(pat,ripl,s,flags=re.DOTALL)
ripl()
是用于执行替换的函数,它以RegexMatch对象的形式接收每个匹配,并返回转换后的部分,然后re.sub()
使用该部分进行替换< / p>