[英]Efficient way to check for expected semicolon position length-delimited text file. Combining many "or" statements
我正在检查文本文件中分号的 position。 我有包含数千行的长度分隔文本文件,如下所示:
AB;2;43234;343;
CD;4;41234;443;
FE53234;543;
FE;5;53;34;543;
我正在使用以下代码来检查分号的正确 position。 如果在我期望的地方缺少分号,则会打印一条语句:
import glob
path = r'C:\path\*.txt'
for fname in glob.glob(path):
print("Checking file", fname)
with open(fname) as f:
content = f.readlines()
for count, line in enumerate(content):
if (line[2:3]!=";"
or line[4:5]!=";"
or line[10:11]!=";"
# really a lot of continuing entries like these
or line[14:15]!=";"
):
print("\nSemikolon expected, but not found!\nrow:", count+1, "\n", fname, "\n", line)
该代码有效。 没有错误被抛出并且它检测到数据行。
我现在的问题是我有很多分号要检查,而且我确实有很多连续的条目,比如
or line[xx:xx]!=";"
我认为这在两点上是低效的:
or
检查在逻辑上是没有效率的。 我认为它可能会更有效地减少运行时间。我正在寻找一种有效的解决方案:
我只想检查是否有我期望的分号。 我需要它们的地方。 我不关心数据字段中的任何额外分号。
只是离开你写的东西:
filename = ...
with open(filename) as file:
lines = file.readlines()
delimiter_indices = (2, 4, 10, 14) # The indices in any given line where you expect to see semicolons.
for line_num, line in enumerate(lines):
if any(line[index] != ";" for index in delimiter_indices):
print(f"{filename}: Semicolon expected on line #{line_num}")
如果该行没有至少 15 个字符,则会引发异常。 此外,像;;;;;;;;;;;;;;;
这样的行在技术上是有效的。
编辑:假设您有一个如下所示的输入文件:
AB;2;43234;343;
CD;4;41234;443;
FE;5;53234;543;
FE;5;53;34;543;
(注意:末尾的空行)我提供的解决方案工作正常。 我没有Semicolon expected on line #...
。
如果您的输入文件以两个空行结尾,这将引发异常。 如果您的输入文件在中间某处包含一个空行,这也会引发异常。 如果文件中的行长度少于 15 个字符(不包括最后一行),这将引发异常。
您可以简单地说,每一行都必须满足两个条件才能被视为有效:
max(delimiter_indices) + 1
字符长)。代码:
for line_num, line in enumerate(lines):
is_long_enough = len(line) >= (max(delimiter_indices) + 1)
has_correct_semicolons = all(line[index] == ';' for index in delimiter_indices)
if not (is_long_enough and has_correct_semicolons):
print(f"{filename}: Semicolon expected on line #{line_num}")
编辑:我的错,为了可读性,我破坏了短路评估。 以下应该工作:
is_valid_line = (len(line) >= (max(delimiter_indices) + 1)) and (all(line[index] == ';' for index in delimiter_indices))
if not is_valid_line:
print(f"{filename}: Semicolon expected on line #{line_num}")
如果行的长度不正确,表达式的后半部分将不会因为短路求值而被求值,这应该可以防止IndexError
。
编辑:因为你有这么多文件,每行有这么多行和这么多分号,你可以在循环之前进行max(delimiter_indices)
计算,以避免为每一行计算该值。 它可能没有太大区别,但您也可以直接迭代文件 object(每次迭代都会产生下一行),而不是在通过lines = file.readlines()
迭代之前将整个文件加载到 memory 中。 这并不是真正需要的,它不像使用all
或any
那样可爱,但我决定将has_correct_semicolons
表达式变成一个实际的循环,该循环遍历定界符索引 - 这样你的错误消息可以更明确一点,指向违规行的违规索引。 此外,当一行太短时,还有一条单独的错误消息。
import glob
delimiter_indices = (2, 4, 10, 14)
max_delimiter_index = max(delimiter_indices)
min_line_length = max_delimiter_index + 1
for path in glob.glob(r"C:\path\*.txt"):
filename = path.name
print(filename.center(32, "-"))
with open(path) as file:
for line_num, line in enumerate(file):
is_long_enough = len(line) >= min_line_length
if not is_long_enough:
print(f"{filename}: Line #{line_num} is too short")
continue
has_correct_semicolons = True
for index in delimiter_indices:
if line[index] != ";":
has_correct_semicolons = False
break
if not has_correct_semicolons:
print(f"{filename}: Semicolon expected on line #{line_num}, character #{index}")
print("All files done")
如果您只想验证行的结构,则可以使用在您的要求发生变化时易于维护的正则表达式:
import re
with open(fname) as f:
for row, line in enumerate(f, 1):
if not re.match(r"[A-Z]{2};\d;\d{5};\d{3};", line):
print("\nSemicolon expected, but not found!\nrow:", row, "\n", fname, "\n", line)
如果你其实并不关心内容,只想查看 position 的;
,您可以将正则表达式简化为: r".{2};.;.{5};.{3};"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.