我希望嵌套循环测试所有元素是否都符合条件,然后返回True。示例:
有一个给定的文本文件:file.txt,其中包含此模式的行:
aaa:bb3:3
fff:cc3:4
字母,冒号,字母数字,冒号,整数,换行符。
通常,我想测试是否所有行都与此模式匹配。但是,在此功能中,我想检查第一列是否仅包含字母。
def opener(file):
#Opens a file and creates a list of lines
fi=open(file).read().splitlines()
import string
res = True
for i in fi:
#Checks whether any characters in the first column is not a letter
if any(j not in string.ascii_letters for j in i.split(':')[0]):
res = False
else:
continue
return res
但是,即使第一列中的所有字符均为字母,该函数也会返回False。我也想问你一个解释。
答案 0 :(得分:1)
您的代码在代码后评估空行-因此False
:
您的文件在最后一行之后包含换行符,因此您的代码将在最后一个数据之后检查该行,这并不能完全满足您的测试-这就是无论输入如何,您都得到False
的原因:
aaa:bb3:3 fff:cc3:4 empty line that does not start with only letters
如果您“特殊对待”空行(如果它们出现在末尾),则可以对其进行修复。如果在填充的行之间有一个空行,则也会返回False
:
with open("t.txt","w") as f:
f.write("""aaa:bb3:3
fff:cc3:4
""")
import string
def opener(file):
letters = string.ascii_letters
# Opens a file and creates a list of lines
with open(file) as fi:
res = True
empty_line_found = False
for i in fi:
if i.strip(): # only check line if not empty
if empty_line_found: # we had an empty line and now a filled line: error
return False
#Checks whether any characters in the first column is not a letter
if any(j not in letters for j in i.strip().split(':')[0]):
return False # immediately exit - no need to test the rest of the file
else:
empty_line_found = True
return res # or True
print (opener("t.txt"))
输出:
True
如果您使用
# example with a file that contains an empty line between data lines - NOT ok
with open("t.txt","w") as f:
f.write("""aaa:bb3:3
fff:cc3:4
""")
或
# example for file that contains empty line after data - which is ok
with open("t.txt","w") as f:
f.write("""aaa:bb3:3
ff2f:cc3:4
""")
您得到:False
答案 1 :(得分:1)
结肠镜检查
您在示例中使用{em> 的情况是一致的:fff:cc3:4
,并且在描述性文本中使用了分号的情况也一致:Letters, semicolon, alphanumeric, semicolon, integer, newline.
我要假设您的意思是冒号(':'),因为这是您键入的字符。如果没有,则应在需要的任何地方将其更改为分号(';')。
您的代码
这是您的代码,以供参考:
def opener(file):
#Opens a file and creates a list of lines
fi=open(file).read().splitlines()
import string
res = True
for i in fi:
#Checks whether any characters in the first column is not a letter
if any(j not in string.ascii_letters for j in i.split(':')[0]):
res = False
else:
continue
return res
您的问题
您询问的问题是该函数始终返回false。您给出的示例在第一个示例和第二个示例之间包含一个空白行。我会提醒您注意那些空白行中的空格或制表符。您可以通过显式捕获空白行并跳过它们来解决此问题:
for i in fi:
if i.isspace():
# skip blank lines
continue
其他一些问题
现在,您可能还没有注意到其他一些事情:
您在函数中提供了一个很好的注释。那应该是一个文档字符串:
def opener(file):
""" Opens a file and creates a list of lines.
"""
您import string
位于函数中间。不要那样做移动导入
到模块顶部:
import string # at top of file
def opener(file): # Not at top of file
您使用open()
打开了文件,但从未关闭过。这正是确切为何将with
关键字添加到python的原因:
with open(file) as infile:
fi = infile.read().splitlines()
您打开了文件,将其全部内容读取到内存中,然后将其拆分为几行 最后丢弃换行符。所有这些使您可以将其用冒号分开并忽略 除了第一个字段之外的所有内容。
只调用文件上的readlines()
会更简单:
with open(file) as infile:
fi = infile.readlines()
res = True
for i in fi:
直接遍历文件本来会更容易 和更简单:
with open(file) as infile:
res = True
for i in infile:
似乎您正在逐步检查开始时给出的整个格式。我怀疑正则表达式会(1)易于编写和维护; (2)以后比较容易理解; (3)执行速度更快。现在,对于这种简单的情况,以及稍后您有更多规则时,都如此:
import logging
import re
bad_lines = 0
for line in infile:
if line.isspace():
continue
if re.match(valid_line, line):
continue
logging.warn(f"Bad line: {line}")
bad_lines += 1
return bad_lines == 0
您的名字不好。您的函数包括名称file
,fi
,i
,j
和res
。唯一没有道理的是file.
考虑到您正在要求人们阅读代码并帮助您发现问题,请请使用更好的名称。如果您仅用file
(相同),infile
,line
,ch
和result
替换这些名称,则代码将更具可读性。如果您使用with
之类的标准Python最佳实践来重组代码,它的可读性将更高。 (而且错误更少!)