python 中的文件验证,更好的方法和原因

File validation in python, the better approach and why

我正在进行一个项目,涉及解析文件以插入到我们的本地数据库中。为了编写高效健壮的代码,我试图了解验证文件的最佳方法是什么。我写了两个 python 脚本:

EXPECTED = 'PubNo|Name|CoverID|Issue|CustomLabel|Split'

with open('test.txt', 'r') as f:
    lines = f.readlines()

test = lines[0].replace(" ", "").strip()

if test[-1] == '|' or test[0] == '|':
    test = test.strip('|')

if test.lower() == EXPECTED.lower():
    print 'Successful Match!'
else:
    print 'Bad match :('

import re

with open('test.txt', 'r') as f:
    lines = f.readlines()

patt = re.compile(r"\|?PubNo\|Name\|CoverID\|Issue\|CustomLabel\|Split\|?", re.I)

test = re.sub(r"\s", "", lines[0])
m = re.match(patt, test)

if m.group():
    print 'Successful Match!'
else:
    print 'Bad match :('

正如我希望的那样,我正在使用简单的字符串文字比较和各种格式来确保 一些 安全,以及一个完全依赖正则表达式的版本。谁能解释这两种方法的优缺点?它们都需要相同的时间来执行并且都相当可读。到目前为止我能看到的唯一优势是使用正则表达式意味着在比较字符串文字之前不必进行太多手动格式化。

假设您没有发现加载整个文件的问题,并且假设您修复了正则表达式(您呈现它的方式程序会在不匹配时中断,您应该检查是否存在匹配,而不是如果其中有一个组)这两个不一样。考虑文件的第一行是:

PubNo | Name | CoverID | Issue | CustomLabel | Split | SomethingMore

您的正则表达式 'validator' 会将其标记为成功,您的字符串比较不会。如果您希望第一列 'validator' 精确匹配该字符串而不匹配其他任何内容,则必须将正则表达式模式更改为 r"\|?PubNo\|Name\|CoverID\|Issue\|CustomLabel\|Split\|?$"。此外,您的正则表达式 'validator' 将消耗 'replacement' 部分中的所有空白字符,包括制表符,而您的字符串比较器不会。

所有条件都相同 - 在这两种情况下,字符串搜索 显着 更快 - 这还不包括正则表达式引擎的加载、准备模式和所有其他所需的支持结构.即使您缓存了模式,并消除了正则表达式的所有缺点,字符串比较仍然会更快。考虑这样的设置:

import re

VALID = "PubNo|Name|CoverID|Issue|CustomLabel|Split"

# prepare the regex patterns
PATTERN_VALID = re.compile(r"\|?{}\|?".format(VALID.replace("|", r"\|")))
PATTERN_STRICT = re.compile(PATTERN_VALID.pattern + "$", re.I)
CLEAR_WHITESPACE = re.compile(r"\s")

# let's not disadvantage the string compare, too
VALID_LOWER = VALID.lower()

def string_valid(data):
    if data.strip("| ").replace(" ", "").lower().startswith(VALID_LOWER):
        return True
    return False

def string_valid_strict(data):
    if data.strip("| \r\n").replace(" ", "").lower() == VALID_LOWER:
        return True
    return False

def regexp_valid(data):
    if PATTERN_VALID.match(CLEAR_WHITESPACE.sub("", data)):
        return True
    return False

def regexp_valid_strict(data):
    if PATTERN_STRICT.match(CLEAR_WHITESPACE.sub("", data)):
        return True
    return False

这将涵盖两种方法的两种情况(严格匹配和仅匹配开头)。您没有考虑构建正则表达式模式来忽略空格,因此您不需要替换,但它不会显着加快速度(实际上,它可能 运行 比这慢)。

所以现在如果你有 3 个文件,比如 good.txtstrict.txtbad.txt 涵盖了所有三种情况,你可以 运行 一个临时测试,比如这个:

# open test files and only get the first lines
with open("good.txt", "r") as g, open("strict.txt", "r") as s, open("bad.txt", "r") as b:
    g = g.readline()  # overwrite is perfectly fine for our test
    s = s.readline()  # overwrite is perfectly fine for our test
    b = b.readline()  # overwrite is perfectly fine for our test

# make sure our functions perform adequately
assert string_valid(g) is regexp_valid(g) is True
assert string_valid_strict(g) is regexp_valid_strict(g) is False
assert string_valid(s) is regexp_valid(s) is True
assert string_valid_strict(s) is regexp_valid_strict(s) is True
assert string_valid(b) is regexp_valid(b) is False
assert string_valid_strict(b) is regexp_valid_strict(b) is False

如果你为每个调用计时(所以 3 次调用,每个循环有 3 条不同的线路),比如说,100,000 次循环,你会得到:

Python 2.7.11

string_valid:        100,000 loops: 0.31 s, per loop:  3.15 µs
string_valid_strict: 100,000 loops: 0.27 s, per loop:  2.76 µs
regexp_valid:        100,000 loops: 1.34 s, per loop: 13.44 µs
regexp_valid_strict: 100,000 loops: 1.38 s, per loop: 13.83 µs

==

Python 3.5.1

string_valid:        100,000 loops: 0.37 s, per loop:  3.73 µs
string_valid_strict: 100,000 loops: 0.33 s, per loop:  3.37 µs
regexp_valid:        100,000 loops: 1.13 s, per loop: 11.28 µs
regexp_valid_strict: 100,000 loops: 1.22 s, per loop: 12.17 µs

这是正则表达式的最佳情况 - 我们甚至正在编译空格删除模式。 OTOH,字符串搜索可以进一步优化(对于非严格示例等,切片而不是 startswith())。

正则表达式很棒,但只在需要时使用。没有理由使用正则表达式来解决像这样的简单问题。