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: ','})

如上,我們實現了忽略數據順序及多值字段順序的差異所帶來的比較結果差異。

除此之外,針對精確比較,我們還可以擴展其比較形式,如比較某兩個目錄下的文件內容,過濾哪些列或選擇哪些列進行比較。


分享到:


相關文章: