本文目录导读:

我来介绍如何编写批量数据格式校验脚本,包含多种常见场景。
基础校验框架
Python实现的基础校验器
import json
import csv
import re
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Any, Optional
class DataValidator:
"""通用数据格式校验器"""
def __init__(self):
self.errors = []
self.warnings = []
def validate_file(self, file_path: str, file_type: str = 'auto') -> bool:
"""校验单个文件"""
file_path = Path(file_path)
if not file_path.exists():
self.errors.append(f"文件不存在: {file_path}")
return False
# 自动检测文件类型
if file_type == 'auto':
file_type = file_path.suffix.lower().lstrip('.')
# 根据文件类型选择校验方法
validators = {
'json': self.validate_json,
'csv': self.validate_csv,
'xml': self.validate_xml,
'yaml': self.validate_yaml,
'txt': self.validate_txt
}
validator = validators.get(file_type)
if not validator:
self.errors.append(f"不支持的文件类型: {file_type}")
return False
return validator(file_path)
def validate_json(self, file_path: Path) -> bool:
"""校验JSON文件"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
# 基本结构校验
if isinstance(data, list):
return self.validate_json_array(data)
elif isinstance(data, dict):
return self.validate_json_object(data)
else:
self.errors.append(f"JSON根元素必须是对象或数组")
return False
except json.JSONDecodeError as e:
self.errors.append(f"JSON解析错误: {e}")
return False
except Exception as e:
self.errors.append(f"读取文件错误: {e}")
return False
def validate_csv(self, file_path: Path) -> bool:
"""校验CSV文件"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
# 读取表头
headers = next(reader, None)
if not headers:
self.errors.append("CSV文件为空")
return False
# 校验每一行
row_num = 1
valid = True
for row in reader:
row_num += 1
if len(row) != len(headers):
self.errors.append(f"第{row_num}行列数不匹配: {len(row)} != {len(headers)}")
valid = False
return valid
except Exception as e:
self.errors.append(f"CSV读取错误: {e}")
return False
def validate_json_array(self, data: List) -> bool:
"""校验JSON数组"""
if not data:
self.warnings.append("JSON数组为空")
return True
valid = True
for i, item in enumerate(data):
if not self.validate_record(item, i):
valid = False
return valid
def validate_record(self, record: Dict, index: int) -> bool:
"""校验单条记录"""
# 子类重写此方法实现具体业务校验
return True
特定格式校验实现
电子邮件格式校验
class EmailValidator(DataValidator):
"""邮箱格式校验器"""
def __init__(self):
super().__init__()
self.email_pattern = re.compile(
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
)
self.domain_list = ['gmail.com', '163.com', 'qq.com', 'outlook.com']
def validate_email(self, email: str) -> bool:
"""校验单个邮箱"""
if not self.email_pattern.match(email):
self.errors.append(f"邮箱格式无效: {email}")
return False
# 校验域名
domain = email.split('@')[1]
if self.domain_list and domain not in self.domain_list:
self.errors.append(f"不支持的邮箱域名: {domain}")
return False
return True
def validate_record(self, record: Dict, index: int) -> bool:
"""校验包含邮箱的记录"""
email = record.get('email', '')
if not email:
self.errors.append(f"第{index}条记录缺少email字段")
return False
return self.validate_email(email)
# 使用示例
validator = EmailValidator()
validator.validate_file('emails.json')
print(validator.errors)
日期格式校验
class DateValidator(DataValidator):
"""日期格式校验器"""
def __init__(self, date_formats: List[str] = None):
super().__init__()
self.date_formats = date_formats or [
'%Y-%m-%d',
'%Y/%m/%d',
'%d-%m-%Y',
'%Y%m%d'
]
def validate_date(self, date_str: str) -> bool:
"""校验日期字符串"""
for fmt in self.date_formats:
try:
datetime.strptime(date_str, fmt)
return True
except ValueError:
continue
self.errors.append(f"日期格式无效: {date_str}")
return False
def validate_record(self, record: Dict, index: int) -> bool:
"""校验包含日期的记录"""
valid = True
# 校验单个日期字段
if 'date' in record:
valid &= self.validate_date(record['date'])
# 校验日期范围
if 'start_date' in record and 'end_date' in record:
start = record['start_date']
end = record['end_date']
if self.validate_date(start) and self.validate_date(end):
if start > end:
self.errors.append(f"开始日期不能晚于结束日期: {start} > {end}")
valid = False
return valid
批量校验脚本
目录批量校验
import os
from concurrent.futures import ThreadPoolExecutor, as_completed
class BatchValidator:
"""批量文件校验器"""
def __init__(self, validators: Dict[str, DataValidator] = None):
self.validators = validators or {
'.json': DataValidator(),
'.csv': DataValidator(),
}
self.results = {}
def validate_directory(self, directory: str, recursive: bool = True) -> Dict:
"""校验目录下所有文件"""
directory = Path(directory)
if not directory.exists():
return {"error": f"目录不存在: {directory}"}
# 获取所有文件
if recursive:
files = list(directory.rglob('*'))
else:
files = list(directory.glob('*'))
# 只处理支持的文件类型
valid_files = [
f for f in files
if f.is_file() and f.suffix.lower() in self.validators
]
# 多线程并行校验
with ThreadPoolExecutor(max_workers=4) as executor:
future_to_file = {
executor.submit(self.validate_single, f): f
for f in valid_files
}
for future in as_completed(future_to_file):
file_path = future_to_file[future]
try:
result = future.result()
self.results[str(file_path)] = result
except Exception as e:
self.results[str(file_path)] = {"error": str(e)}
return self.results
def validate_single(self, file_path: Path) -> Dict:
"""校验单个文件"""
file_type = file_path.suffix.lower()
validator = self.validators.get(file_type)
if not validator:
return {"error": f"不支持的文件类型: {file_type}"}
valid = validator.validate_file(file_path)
return {
"valid": valid,
"errors": validator.errors,
"warnings": validator.warnings
}
配置驱动的校验器
import yaml
class ConfigDrivenValidator(DataValidator):
"""配置驱动的校验器"""
def __init__(self, config_path: str):
super().__init__()
with open(config_path, 'r', encoding='utf-8') as f:
self.config = yaml.safe_load(f)
def validate_record(self, record: Dict, index: int) -> bool:
"""根据配置校验记录"""
valid = True
for field, rules in self.config.get('fields', {}).items():
value = record.get(field)
# 必填校验
if rules.get('required', False) and not value:
self.errors.append(f"第{index}条记录缺少必填字段: {field}")
valid = False
continue
if value is None:
continue
# 类型校验
expected_type = rules.get('type')
if expected_type:
type_map = {
'string': str,
'number': (int, float),
'integer': int,
'boolean': bool,
}
expected = type_map.get(expected_type)
if expected and not isinstance(value, expected):
self.errors.append(
f"第{index}条记录字段{field}类型错误: "
f"期望{expected_type}, 实际{type(value).__name__}"
)
valid = False
# 正则校验
pattern = rules.get('pattern')
if pattern and not re.match(pattern, str(value)):
self.errors.append(
f"第{index}条记录字段{field}格式不符合要求: {value}"
)
valid = False
# 长度/范围校验
if 'min_length' in rules and len(str(value)) < rules['min_length']:
self.errors.append(
f"第{index}条记录字段{field}长度不足: {value}"
)
valid = False
if 'max_length' in rules and len(str(value)) > rules['max_length']:
self.errors.append(
f"第{index}条记录字段{field}长度超限: {value}"
)
valid = False
# 枚举值校验
if 'enum' in rules and value not in rules['enum']:
self.errors.append(
f"第{index}条记录字段{field}值不在允许范围内: {value}"
)
valid = False
return valid
# 配置文件示例 (validate_config.yaml)
"""
fields:
name:
type: string
required: true
min_length: 2
max_length: 50
age:
type: integer
required: true
min: 0
max: 150
email:
type: string
pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
gender:
type: string
enum: ['male', 'female', 'other']
"""
# 使用示例
validator = ConfigDrivenValidator('validate_config.yaml')
validator.validate_file('data.json')
print(f"错误数: {len(validator.errors)}")
for error in validator.errors:
print(f" - {error}")
命令行工具
#!/usr/bin/env python3
import argparse
import sys
from pathlib import Path
def main():
parser = argparse.ArgumentParser(description='批量数据格式校验工具')
parser.add_argument('path', help='要校验的文件或目录路径')
parser.add_argument('-t', '--type', choices=['json', 'csv', 'yaml', 'auto'],
default='auto', help='文件类型')
parser.add_argument('-r', '--recursive', action='store_true',
help='递归处理子目录')
parser.add_argument('-o', '--output', help='输出错误报告到文件')
parser.add_argument('-v', '--verbose', action='store_true',
help='详细输出')
args = parser.parse_args()
# 创建校验器
validator = DataValidator()
batch_validator = BatchValidator()
path = Path(args.path)
if path.is_file():
# 校验单个文件
result = validator.validate_file(path, args.type)
if result:
print(f"[✓] 校验通过: {path}")
else:
print(f"[✗] 校验失败: {path}")
if args.verbose:
for error in validator.errors:
print(f" Error: {error}")
for warning in validator.warnings:
print(f" Warning: {warning}")
elif path.is_dir():
# 批量校验目录
results = batch_validator.validate_directory(path, args.recursive)
# 统计结果
total = len(results)
passed = sum(1 for r in results.values() if r.get('valid'))
failed = total - passed
print(f"\n校验结果统计:")
print(f" 总数: {total}")
print(f" 通过: {passed}")
print(f" 失败: {failed}")
if args.verbose:
for file_path, result in results.items():
status = "✓" if result.get('valid') else "✗"
print(f"\n[{status}] {file_path}")
for error in result.get('errors', []):
print(f" Error: {error}")
# 输出到文件
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
json.dump({
'path': str(path),
'results': results if path.is_dir() else [{
'errors': validator.errors,
'warnings': validator.warnings
}]
}, f, ensure_ascii=False, indent=2)
print(f"\n报告已保存到: {args.output}")
if __name__ == '__main__':
main()
使用示例
# 校验单个文件 python validator.py data.json # 校验目录下所有文件 python validator.py /path/to/data -r # 指定文件类型并输出详细错误 python validator.py data.csv -t csv -v # 输出错误报告 python validator.py /path/to/data -o report.json
这些代码提供了一个完整的批量数据格式校验框架,可以根据实际需求进行扩展和定制。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播