Python实现两文本内容(数据)的一致性校验

Python实现两文本内容(数据)的一致性校验

比对文件说明

在日常测试开发工作中,经常会遇到比较两个文件一致性的情况,接下来分享两种常用的python解决方案,首先看如下两个文件。

如下file_one与file_two两个文件,文件内容均记录了姓名、年龄、籍贯、爱好四个字段,以"\t"分割,其中爱好字段是多值字段,以","分割。

Python实现两文本内容(数据)的一致性校验

file_one.txt

Python实现两文本内容(数据)的一致性校验

file_two.txt

两者有什么区别:

  1. file_one与file_two均含两条数据,两条数据顺序不同。
  2. Jom、Tim在两个文件中爱好(多值)字段的值顺序不同。

difflib方法

#!-*- coding:UTF-8 -*- 

#!/usr/bin/env python
import difflib

def compare_file(file1, file2):
def read_file(file_name):
with open(file_name, 'r') as read_file:
content = read_file.readlines()
return content
text1 = read_file(file1)
text2 = read_file(file2)
# 创建HtmlDiff 对象
diff = difflib.HtmlDiff()
# 通过make_file 方法输出 html 格式的对比结果
result = diff.make_file(text1, text2)
# 将结果写入到result_comparation.html文件中
with open('comparation.html', 'w') as result_file:
result_file.write(result)

if __name__ == "__main__":
compare_file('file_one.txt', 'file_two.txt')

结果html文件如下

Python实现两文本内容(数据)的一致性校验

通过difflib模块结果不难发现file_one与file_two存在的异同,如上。

Python实现两文本内容(数据)的一致性校验

精确比较

在实际工作场景,往往数据的顺序或者某多值字段顺序不同,不影响数据本身的一致性,比如Jom的爱好在两个文件中的顺序不同,但仍然视为相同,不应该被判断为不同。下面我们通过python实现精确比较,详见如下源码。

自定义File类

  • 实现文件存在判断。
  • 实现文件读取,读取为list,list中的每个元素即为每一行以"\t"分割的列表。
class File(object):

def is_exist_file(self, path):
return os.path.isfile(path)


def format_file(self, filename, mode='rb', encoding="utf-8", errors='strict', buffering=1):
assert self.is_exist_file(filename), "{0} file not found!".format(filename) # 校验文件是否存在
file_content_format_list = []
with codecs.open(filename, mode=mode, encoding=encoding, errors=errors, buffering=buffering) as _openfile:
_file_content = _openfile.readlines()
field_format = len(_file_content[0].strip('\r\n').strip('\n').split('\t'))
for line in _file_content:
_line = line.strip('\r\n').strip('\n')
if len(_line) != 0:
_split_list = _line.split("\t")
_field_format = len(_split_list)
assert field_format == _field_format, 'Not consistent with the number of file fields!filename:{0}'.format(filename) # 校验字段格式是否一致
file_content_format_list.append(_split_list)
return file_content_format_list

自定义CompareFile类

  • 文件预处理,针对多值列进行排序后按序组合,避免实际结果与预期结果因多值列排序不同导致误报错。
  • 实现文件内容比较,即嵌套list的比较。
class CompareFile(object):
def _preprocessing_file(self, expected_file, actual_files, columns_space_mark=None):
"""
文件预处理,针对多之列进行排序后组合,避免实际结果与预期结果因多之列排序不同导致误报错。
:param expected_file: 期望文件绝对路径
:param actual_files: 实际文件绝对路径
:param encoding:
:param errors:
:param buffering:
:param columns_space_mark: 多之列序号与列间隔符字典,{'3':';',...}表示第三列间隔符号为“;”,从1开始
:return:期望文件内容列表、实际文件内容列表
"""
def column_sort(file, mode='rb', encoding="utf-8", errors='strict', buffering=1,
columns_space_mark=columns_space_mark):
format_file = File().format_file(file, mode=mode, encoding=encoding, errors=errors, buffering=buffering)
if columns_space_mark is not None:
_exist = False
_columns_space_mark = literal_eval(str(columns_space_mark))
for _line in format_file:
for column_index, space_mark in _columns_space_mark.iteritems(): # 每行数据中多值列,按照多之列间隔符号拆分后排序,再组合。
if space_mark in _line[int(column_index) - 1]:
_exist = True
_tmp_list = _line[int(column_index) - 1].split(space_mark)
_tmp_list.sort()
_line[int(column_index) - 1] = space_mark.join(_tmp_list)
return format_file
format_expected_content = column_sort(expected_file)
actual_files_content = column_sort(actual_files)
return format_expected_content, actual_files_content


def _compare(self, _format_expected_content, actual_files_content):
"""
:param _format_expected_content: list
:param _format_actual_content: list
:return:
"""
# 校验数据数量是否一致
assert len(_format_expected_content) == len(actual_files_content), '[Error Code 200]The actual number of results does not accord with the expections:\n expect number:{0}\nactual number:{1}'.format(
len(_format_expected_content),
len(actual_files_content))
only_expected_exist = []
# 遍历期望结果,遍历实际结果,如果期望结果存在实际结果中,则删除实际结果列表对应值
for expected_line in _format_expected_content:
exist = False
for actual_index, actual_line in enumerate(actual_files_content):
if expected_line == actual_line:
exist = True
actual_files_content.pop(actual_index)
break
# 如果期望结果不存在实际结果中,则添加中列表中。
if not exist:
only_expected_exist.append(expected_line)
# only_expected_exist、only_actual_exist都为空,则说明正常,否则异常。
if only_expected_exist != [] or len(actual_files_content) > 0:
assert False, '[Error Code 201]The actual results of results does not accord with the expections:\nonly_expected_exist:Num:{0},Data{1}\nonly_actual_exist:Num:{2},Data:{3}'.format(
len(only_expected_exist), only_expected_exist,
len(actual_files_content),
actual_files_content)

def complete_compare(self, expected_file, actual_files, columns_space_mark=None):
_format_expected_content, _format_actual_content = self._preprocessing_file(expected_file, actual_files,columns_space_mark)
self._compare(_format_expected_content, _format_actual_content)

if __name__ == "__main__":
CompareFileKeyword().complete_compare('file_one.txt', 'file_two.txt',columns_space_mark={4: ','})

如上,我们实现了忽略数据顺序及多值字段顺序的差异所带来的比较结果差异。

除此之外,针对精确比较,我们还可以扩展其比较形式,如比较某两个目录下的文件内容,过滤哪些列或选择哪些列进行比较。


分享到:


相關文章: