我试图在python中编写一个正则表达式来识别短语的实例"为"并且"为"在文本中,有可能找到单词介于两者之间的实例,例如,"为#34;弹吉他。我只希望这能找到第一个单词" for"之后"播放"或者"播放"但是,我无法弄清楚如何编写正则表达式。
我目前的代码是这样的:
def play_finder(doc)
playre = re.compile(r'\bplay[s|e][d]?\b.*\bfor\b\s\b')
if playre.findall(doc):
for inst in playre.findall(doc):
playstr = inst
print(playstr)
mytext = "He played for four hours last night. He plays guitar for the foo pythers. He won an award for his guitar playing."
play_finder(mytext)
我希望我能够从mytext
中提取两个实例; "参加四场比赛。并且"为#34;。弹吉他。
相反,我的代码所发现的是:
"他昨晚打了四个小时。他为foo pythers弹吉他。他因为#34而获奖。
所以它跳过了第一个和第二个,只找到了最后一个。
如何重写正则表达式以使其停止跳过""的第一个和第二个实例。在句子中,并确定他们两个?
编辑:在应用我提供的解决方案后,另一个问题变得明显。给出多个句子,例如:
"他打了八个小时。看起来他一直都在继续。"
我不希望正则表达式识别"他玩了8小时。好像他继续了#34;作为匹配模式。有没有办法阻止它寻找" for"如果它遇到了句号?
答案 0 :(得分:1)
你可以试试这个,
\bplay(?:s|ed).*?for\b
脚本的正则表达式存在一些错误。
playre = re.compile(r'\bplay[s|e][d]?\b.*\bfor\b\s\b')
[s|e]
:对于逻辑表达式不可行,因为[]
是character class
,并且只表示允许的一个字符.*
:greed(*) search
似乎与可能的最大长度匹配字符串匹配。答案 1 :(得分:0)
你误解了方括号的使用。它们创建一个字符类,它匹配括号之间枚举的字符集中的单个字符。因此[s|e]
匹配s
或|
或e
。
此外,单词边界只是一个断言。如果前一个字符是“单词”字符而下一个字符不是,则匹配,反之亦然;但它不会提升字符串中的位置。因此,例如,\s\bfor\b\s
是多余的;我们已经知道\s
匹配空白(非单词),for
由单词字符组成。您的意思是\sfor\s
,因为删除的\b
条件不会更改匹配的内容。
尝试
r'\bplay(?:s|ed)?\s+(?:\w+\s+)??for\s+\w+'
(?:\w+\s+)??
允许for
之前的单个可选字词。第二个问号使得捕获非贪婪,即它匹配仍然允许表达式匹配的最短可能字符串,而不是最长的字符串。你不会想要允许无限次重复(因为那时你会匹配,例如“在他坐下来之前玩过另一个游戏”),但是你可以考虑用例如??
替换{0,3}?
。 (?:...)
在“for”之前允许最多三个单词。
我们使用(...)
代替findall
来使分组括号不被捕获;否则,if findall: for findall
将返回捕获的子匹配列表,而不是整个匹配。
for match in findall
效率低下;你只需要{{1}},如果没有匹配就会简单地迭代零次。
更一般地说,使用正则表达式来处理更高级别的语法模式往往不能令人满意。语法解析器(甚至某种类型的浅层解析)更好地告诉您何时某些单词是名词短语的可选属性或修饰符的组成部分,或者“play”应该作为名词进行分析。考虑
他打了 - 或者更确切地说,轻拍他的手指并且哼了一声 - 持续了三分钟。
我在一年中第三次扮演另一个愚蠢但并非完全离谱的角色。
对许多球员来说,这对老鹰队来说是一种令人反感的进攻游戏。
布雷特扮演双簧管,虽然他认为这是为了懦夫。
有些剧本适合傻瓜。
答案 2 :(得分:0)
有人回答我需要懒惰的.*?
然后删除他们的答案。我不确定为什么,因为那很有效。因此,我现在使用的代码是:
(r'\bplay[s|e][d]?\b.*?\bfor\b\s\b')
@ThmLee我尝试了你的建议:
\bplay(s|ed).*?for\b
我(显然)不是正则表达式的专家,但它似乎不能正常工作。而不是输出“播放”和“弹吉他”的行,它只输出“s”和“ed”。