1

我想要嵌套循环来测试是否所有元素都符合条件,然后返回 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。我也想请你解释一下。

4

2 回答 2

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

于 2019-02-17T15:42:19.977 回答
1

结肠镜检查

  1. ASCII 和 UNICODE 都将字符 0x3A 定义为COLON。这个字符看起来像两个点,一个在另一个上::

  2. ASCII 和 UNICODE 都将字符 0x3B 定义为SEMICOLON。这个字符看起来像一个逗号上的点:;

您在示例中对冒号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

其他一些问题

现在这里有一些你可能没有注意到的其他事情:

  1. 你在你的函数中提供了一个很好的评论。那应该是一个文档字符串:

    def opener(file):
        """ Opens a file and creates a list of lines.
        """
    
  2. import string在你的职能中间。不要那样做。将导入移至模块顶部:

    import string # at top of file
    
    def opener(file):   # Not at top of file
    
  3. 您打开文件时open()从未关闭过它。这正是with关键字添加到 python 的原因:

    with open(file) as infile:
        fi = infile.read().splitlines()
    
  4. 您打开文件,将其全部内容读入内存,然后将其拆分为几行,最后丢弃换行符。所有这些都是为了您可以用冒号拆分它并忽略除第一个字段之外的所有内容。

    只调用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:
    
  5. 似乎您正在努力检查您在开始时提供的整个格式。我怀疑正则表达式会(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
    
  6. 你的名字很糟糕。您的函数包括名称filefiijres。唯一没有意义的是file.

    考虑到您要求人们阅读您的代码并帮助您找到问题,使用更好的名称。如果您只是将这些名称替换为file(same), infile, line, chresult那么代码将变得更具可读性。如果您使用标准 Python 最佳实践(例如 )重构代码with,它的可读性会更高。(并且错误更少!)

于 2019-02-17T16:59:54.520 回答