正则表达式:不匹配以换行符 (\n) 结尾的字符串和行尾锚 ($)

Posted

技术标签:

【中文标题】正则表达式:不匹配以换行符 (\\n) 结尾的字符串和行尾锚 ($)【英文标题】:Regex: don't match string ending with newline (\n) with end-of-line anchor ($)正则表达式:不匹配以换行符 (\n) 结尾的字符串和行尾锚 ($) 【发布时间】:2018-07-21 16:04:36 【问题描述】:

我不知道如何匹配一个字符串,但如果它有一个尾随换行符 (\n),这似乎是自动剥离的:

import re

print(re.match(r'^foobar$', 'foobar'))
# <_sre.SRE_Match object; span=(0, 6), match='foobar'>

print(re.match(r'^foobar$', 'foobar\n'))
# <_sre.SRE_Match object; span=(0, 6), match='foobar'>

print(re.match(r'^foobar$', 'foobar\n\n'))
# None

对我来说,第二种情况也应该返回None。 当我们使用$ 设置模式的结尾时,比如^foobar$,它应该只匹配foobar 这样的字符串,而不是foobar\n

我错过了什么?

【问题讨论】:

究竟什么是单​​行字符串,您是如何阅读的?您是在读取二进制文件并自己解析吗? 我删除了“单行”一词。这是误导性的,没有增加问题的价值。否则,不,我不解析文件。我只需要检查一个简单字符串的模式,就像我的例子一样。 【参考方案1】:

这是$ 的定义行为,可以在@zvone 链接的文档中阅读,甚至可以在https://regex101.com 上阅读:

$ 断言字符串末尾的位置,或字符串末尾的行终止符之前(如果有的话)

您可以使用明确的否定前瞻来应对这种行为:

import re

print(re.match(r'^foobar(?!\n)$', 'foobar'))
# <_sre.SRE_Match object; span=(0, 6), match='foobar'>

print(re.match(r'^foobar(?!\n)$', 'foobar\n'))
# None

print(re.match(r'^foobar(?!\n)$', 'foobar\n\n'))
# None

【讨论】:

【参考方案2】:

documentation 是这么说 $ 字符的:

匹配字符串的结尾或就在结尾处的换行符之前 字符串,并且在 MULTILINE 模式下也匹配换行符之前。

因此,如果没有 MULTILINE 选项,它会完全匹配您尝试的前两个字符串:'foobar''foobar\n',但不匹配 'foobar\n\n',因为这不是字符串末尾的换行符。

另一方面,如果您选择MULTILINE 选项,它将匹配任何行的结尾:

>>> re.match(r'^foobar$', 'foobar\n\n', re.MULTILINE)
<_sre.SRE_Match object; span=(0, 6), match='foobar'>

当然,这在以下情况下也会匹配,可能是也可能不是你想要的:

>>> re.match(r'^foobar$', 'foobar\nanother line\n', re.MULTILINE)
<_sre.SRE_Match object; span=(0, 6), match='foobar'>

为了不匹配结尾的换行符,use the negative lookahead as DeepSpace wrote。

【讨论】:

【参考方案3】:

你更可能不需要$,而是\Z

>>> print(re.match(r'^foobar\Z', 'foobar\n'))
None
\Z 仅匹配字符串的末尾。

【讨论】:

这就是要走的路。我怀疑消极的前瞻是一个肮脏的黑客。谢谢! 谢谢,帮了大忙!

以上是关于正则表达式:不匹配以换行符 (\n) 结尾的字符串和行尾锚 ($)的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式

正则表达式

notepad正则表达式

正则表达式匹配换行

Linux 正则表达

正则表达式学习记录