Python中的正则表达式负向先行行为

2 投票
4 回答
2964 浏览
提问于 2025-04-17 05:56

我有一个正则表达式,它应该能找到一行中的最多10个单词。也就是说,它应该包括换行符前面的那个单词,但不包括换行符后面的单词。我在使用一个负向前瞻来处理换行符"\n"。

a = re.compile(r"((\w)+[\s /]){0,10}(?<!\n)")
r = a.search("THe car is parked in the garage\nBut the sun is shining hot.")

当我执行这个正则表达式并调用方法r.group()时,我得到的是整个句子,但最后一个单词后面有个句号。我原本只想要换行符前的完整字符串,也就是“车停在车库里\n”。我在使用负向前瞻时到底哪里出错了呢……?

4 个回答

0

如果我理解得没错,你想要读取最多10个单词,或者遇到第一个换行符,先到者为准:

((?:(?<!\n)\w+\b[\s.]*){0,10})

这里使用了一个负向前瞻,但它是在单词匹配之前,所以它会阻止获取换行符后面的任何单词。

这个方法可能需要根据不完美的输入进行一些调整,但这算是一个开始。

0

在这个任务中,有一个锚点 $ 用来找到字符串的结尾,配合修饰符 re.MULTILINE/re.M,它可以找到行的结尾。所以你最终会得到类似这样的东西:

(\b\w+\b[.\s /]{0,2}){0,10}$

你可以在 这里查看 Regexr

\b 是一个单词边界。我在我的例子中加入了 [.\s /]{0,2} 来匹配一个点后面跟着一个空格。如果你不想要点的话,你需要把这一部分至少设为可选,比如 [\s /]?,否则它会在最后一个单词缺失,然后 \s 就会匹配到 \n

更新/想法 2

好的,也许我在第一个解决方案中误解了你的问题。

如果你只是想避免匹配换行符并继续到第二行,那就不要允许换行符。问题在于,换行符被你字符类中的 \s 匹配了。\s 是一个空白字符的类,它也包括换行符 \r\n

你已经在类中有一个空格了,所以如果你想允许制表符,可以把 \s 替换成 \t,这样就可以不使用回顾了。当然,要把字符类设为可选,否则最后一个单词也会不匹配。

((\w)+[\t /]?){0,10}

你可以在 这里查看 Regexr

0

我不太明白你为什么要用负向前瞻。你提到你想在换行符之前最多有10个单词。下面的正则表达式应该可以满足这个需求。它使用了正向前瞻,确保在这些单词后面确实有一个换行符。而且在查找单词时,建议使用 `b\w+\b`,而不是你之前用的那种方式。

/(\b\w+\b)*(?=.*\\n)/

Python :

result = re.findall(r"(\b\w+\b)*(?=.*\\n)", subject)

解释:

# (\b\w+\b)*(?=.*\\n)
# 
# Match the regular expression below and capture its match into backreference number 1 «(\b\w+\b)*»
#    Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
#    Note: You repeated the capturing group itself.  The group will capture only the last iteration.  Put a capturing group around the repeated group to capture all iterations. «*»
#    Assert position at a word boundary «\b»
#    Match a single character that is a “word character” (letters, digits, etc.) «\w+»
#       Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
#    Assert position at a word boundary «\b»
# Assert that the regex below can be matched, starting at this position (positive lookahead) «(?=.*\\n)»
#    Match any single character that is not a line break character «.*»
#       Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
#    Match the character “\” literally «\\»
#    Match the character “n” literally «n»

你可能还需要考虑到你的字符串中可能没有换行符(\n)。

撰写回答