我有一个包含类似
的文件#comment
#comment
不是评论#comment
#comment
不是评论
我试图逐行读取文件,只捕获不以#开头的行。我的代码/正则表达式出了什么问题?
import re
def read_file():
pattern = re.compile("^(?<!# ).*")
with open('list') as f:
for line in f:
print pattern.findall(line)
原始代码捕获所有内容而非预期内容。
答案 0 :(得分:11)
另一种简单的方法是仅检查您阅读的每一行的第一个char
是否包含#
字符:
def read_file():
with open('list') as f:
for line in f:
if not line.lstrip().startswith('#'):
print line
答案 1 :(得分:11)
Iron Fist显示了你应该这样做的方式;但是,如果你想知道你的正则表达式有什么问题,应该是这样的:
^[^#].*
说明:
^
- 匹配行首。[^#]
- 匹配不是#
的内容。 [^...]
就是说你不匹配的东西(只需将...
替换为你不想匹配的任何字符。例如,[^ABC123]
将匹配一个不是A,B的字符,C,1,2或3.不要让表示行/字符串开头的^
在这里混淆你。这两个^
是完全无关的。.*
- 匹配零或更多其他内容。修改强>
^(?<!# ).*
不区分# comment
和not a comment
的原因是(?<!#)
在当前位置之前检查文本。引擎在字符串开头之后的第一个符号之前查找#
,并且由于字符串开头之前没有#
,因此任何行都匹配.*
子模式。要真正检查第一个符号是否为#
,您只需使用^#.*
正则表达式。或者,如果可以有前导空格^\s*#
。
答案 2 :(得分:4)
由于:
(?!# )
否定 Lookahead - 断言无法匹配下面的正则表达式
(?<!# )
否定 Lookbehind - 断言无法匹配正则表达式#
。
来自regex101
这意味着它只匹配#
。所以我的意思是:
>>> re.search('foo(?!bar)', 'foobar')
>>> re.search('foo(?<!bar)', 'foobar') # doesn't work
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> re.search('(?<!bar)foo', 'barfoo')
>>> re.search('(?!bar)foo', 'barfoo') # doesn't work
<_sre.SRE_Match object; span=(3, 6), match='foo'>
这是因为您使用了错误的令牌。所以答案很简单:
如果在
(?!bar)
之后不想要某些字符串,请使用bar
。
如果在(?<!bar)
之前不想要某些字符串,请使用bar
。
答案 3 :(得分:1)
在这种情况下使用match
功能 - 因为它会在开头检查。
所以表达式为\s*[^#]
- 为了理智,我使用\s
来传递空格。
OP的代码将是 -
def read_file():
pattern = re.compile("\s*[^#]")
with open(r"C:\test.txt") as f:
for line in f:
if pattern.match(line):
print line
read_file()
编辑 -
有点解释为什么OP的模式不起作用 -
当您使用.
时,除换行符外,它意味着全部。所以当你写^(?<!# ).*
时,它意味着any
字符(除了换行符,它包含#
该死的!)之前没有#
- 最终它变成任何字符串(除了换行符)以any
字符开头。
参见 LIVE DEMO
解决方案:
尝试像negation
^(?<!# )[^#]