正则表达式匹配返回到一个句点或字符串的开头

6
我希望您能匹配一个单词,然后获取该单词之前的所有内容,直到第一个句点或字符串的开头。
例如,给定以下字符串,搜索单词“regex”:
s = 'Do not match this. Or this. Or this either. I like regex. It is hard, but regex is also rewarding.'

它应该返回:
>> I like regex.
>> It is hard, but regex is also rewarding.

我正在努力理解前瞻和后顾,但是(似乎)你不能轻易地回望,只有在你匹配的模式紧挨着时才可以。我可以用以下代码接近:

pattern = re.compile(r'(?:(?<=\.)|(?<=^))(.*?regex.*?\.)')

但它会给我第一个周期,然后是从“regex”开始的所有内容:
>> Do not match this. Or this. Or this either. I like regex.  # no!
>> It is hard, but regex is also rewarding.                   # correct
1个回答

7
你不需要使用顺序环视来实现这个功能。反转字符类是你最好的朋友:
(?:[^\s.][^.]*)?regex[^.]*\.?

或者
[^.]*regex[^.]*\.?

这样,您可以获取单词“regex”之前的所有字符,并禁止这些字符中出现点号。

第一个模式去除左侧的空格,第二个模式更基础一些。

关于您的模式:

请不要忘记,正则表达式引擎从字符串的左侧到右侧的每个位置都会尝试成功匹配。这就是为什么像(?:(?<=\.)|(?<=^)).*?regex这样的模式并不总是返回点号或字符串开头和单词“regex”之间最短的子字符串,即使您使用非贪婪量词也是如此。最左边的位置总是获胜,非贪婪量词采用字符,直到下一个子模式成功。

顺便提一下,否定字符类可能很有用:
为了缩短(?:(?<=\.)|(?<=^)),您可以编写(?<![^.])


如果我理解你的简短版本,* 会抓取任何东西,从本质上讲是向后直到碰到句点,同样也是向前的吗? - JeffThompson
1
@JeffThompson:不,正则表达式引擎从左到右工作,并测试字符串中的所有位置,直到模式成功匹配。在regex101.com上进行测试,并使用调试器查看发生了什么。 - Casimir et Hippolyte
1
@JeffThompson: [^.]* 匹配任何字符并逐个返回,直到下一个子模式(“正则表达式”)成功。如果不起作用,则正则表达式引擎尝试从字符串的下一个位置开始相同的操作。 - Casimir et Hippolyte

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接