185 lines
5.3 KiB
Python
185 lines
5.3 KiB
Python
|
|
"""
|
|||
|
|
数据验证工具
|
|||
|
|
提供各种数据验证功能
|
|||
|
|
"""
|
|||
|
|
import re
|
|||
|
|
from typing import Tuple, Any, Optional
|
|||
|
|
from config import FieldType
|
|||
|
|
|
|||
|
|
|
|||
|
|
class Validator:
|
|||
|
|
"""数据验证器"""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def validate_field_name(name: str) -> Tuple[bool, str]:
|
|||
|
|
"""
|
|||
|
|
验证字段名称
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
name: 字段名称
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
(是否有效, 错误信息)
|
|||
|
|
"""
|
|||
|
|
if not name:
|
|||
|
|
return False, "字段名称不能为空"
|
|||
|
|
|
|||
|
|
# 字段名只能包含字母、数字、下划线和点号
|
|||
|
|
pattern = r'^[a-zA-Z][a-zA-Z0-9_.]*$'
|
|||
|
|
if not re.match(pattern, name):
|
|||
|
|
return False, "字段名称只能以字母开头,包含字母、数字、下划线和点号"
|
|||
|
|
|
|||
|
|
if len(name) > 255:
|
|||
|
|
return False, "字段名称长度不能超过255个字符"
|
|||
|
|
|
|||
|
|
return True, ""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def validate_domain(domain: str) -> Tuple[bool, str]:
|
|||
|
|
"""
|
|||
|
|
验证域名
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
domain: 域名
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
(是否有效, 错误信息)
|
|||
|
|
"""
|
|||
|
|
if not domain:
|
|||
|
|
return False, "域名不能为空"
|
|||
|
|
|
|||
|
|
# 域名只能包含字母、数字和下划线
|
|||
|
|
pattern = r'^[a-zA-Z][a-zA-Z0-9_]*$'
|
|||
|
|
if not re.match(pattern, domain):
|
|||
|
|
return False, "域名只能以字母开头,包含字母、数字和下划线"
|
|||
|
|
|
|||
|
|
if len(domain) > 100:
|
|||
|
|
return False, "域名长度不能超过100个字符"
|
|||
|
|
|
|||
|
|
return True, ""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def validate_field_value(value: str, field_type: FieldType) -> Tuple[bool, str]:
|
|||
|
|
"""
|
|||
|
|
验证字段值是否符合类型
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
value: 字段值
|
|||
|
|
field_type: 字段类型
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
(是否有效, 错误信息)
|
|||
|
|
"""
|
|||
|
|
if not value:
|
|||
|
|
return True, "" # 空值允许
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
if field_type == FieldType.INT:
|
|||
|
|
int(value)
|
|||
|
|
elif field_type in [FieldType.FLOAT, FieldType.DOUBLE]:
|
|||
|
|
float(value)
|
|||
|
|
elif field_type == FieldType.BOOLEAN:
|
|||
|
|
if value.lower() not in ['true', 'false', '0', '1']:
|
|||
|
|
return False, "布尔值必须是 true/false 或 0/1"
|
|||
|
|
elif field_type == FieldType.DATETIME:
|
|||
|
|
from datetime import datetime
|
|||
|
|
# 尝试解析常见的日期时间格式
|
|||
|
|
datetime.fromisoformat(value.replace('Z', '+00:00'))
|
|||
|
|
|
|||
|
|
return True, ""
|
|||
|
|
except ValueError as e:
|
|||
|
|
return False, f"值 '{value}' 不符合类型 {field_type.value}: {str(e)}"
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def validate_range(min_val: Optional[str], max_val: Optional[str],
|
|||
|
|
field_type: FieldType) -> Tuple[bool, str]:
|
|||
|
|
"""
|
|||
|
|
验证范围值
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
min_val: 最小值
|
|||
|
|
max_val: 最大值
|
|||
|
|
field_type: 字段类型
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
(是否有效, 错误信息)
|
|||
|
|
"""
|
|||
|
|
if not min_val or not max_val:
|
|||
|
|
return True, ""
|
|||
|
|
|
|||
|
|
# 验证最小值
|
|||
|
|
is_valid, error = Validator.validate_field_value(min_val, field_type)
|
|||
|
|
if not is_valid:
|
|||
|
|
return False, f"最小值无效: {error}"
|
|||
|
|
|
|||
|
|
# 验证最大值
|
|||
|
|
is_valid, error = Validator.validate_field_value(max_val, field_type)
|
|||
|
|
if not is_valid:
|
|||
|
|
return False, f"最大值无效: {error}"
|
|||
|
|
|
|||
|
|
# 比较大小
|
|||
|
|
try:
|
|||
|
|
if field_type == FieldType.INT:
|
|||
|
|
if int(min_val) > int(max_val):
|
|||
|
|
return False, "最小值不能大于最大值"
|
|||
|
|
elif field_type in [FieldType.FLOAT, FieldType.DOUBLE]:
|
|||
|
|
if float(min_val) > float(max_val):
|
|||
|
|
return False, "最小值不能大于最大值"
|
|||
|
|
except ValueError:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
return True, ""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def validate_version(version: str) -> Tuple[bool, str]:
|
|||
|
|
"""
|
|||
|
|
验证版本号
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
version: 版本号
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
(是否有效, 错误信息)
|
|||
|
|
"""
|
|||
|
|
if not version:
|
|||
|
|
return False, "版本号不能为空"
|
|||
|
|
|
|||
|
|
# 支持 v1, v1.0, v1.0.0 等格式
|
|||
|
|
pattern = r'^v?\d+(\.\d+)*$'
|
|||
|
|
if not re.match(pattern, version):
|
|||
|
|
return False, "版本号格式不正确,应为 v1, v1.0, v1.0.0 等格式"
|
|||
|
|
|
|||
|
|
return True, ""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def validate_code(code: str, language: str) -> Tuple[bool, str]:
|
|||
|
|
"""
|
|||
|
|
验证代码语法(简单检查)
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
code: 代码字符串
|
|||
|
|
language: 编程语言
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
(是否有效, 错误信息)
|
|||
|
|
"""
|
|||
|
|
if not code or not code.strip():
|
|||
|
|
return False, "代码不能为空"
|
|||
|
|
|
|||
|
|
# 基本的语法检查
|
|||
|
|
if language in ['C', 'CPP']:
|
|||
|
|
# 检查是否有基本的C/C++结构
|
|||
|
|
if '{' in code and '}' not in code:
|
|||
|
|
return False, "代码括号不匹配"
|
|||
|
|
if code.count('{') != code.count('}'):
|
|||
|
|
return False, "代码括号数量不匹配"
|
|||
|
|
|
|||
|
|
elif language == 'Python':
|
|||
|
|
# 检查Python缩进
|
|||
|
|
try:
|
|||
|
|
compile(code, '<string>', 'exec')
|
|||
|
|
except SyntaxError as e:
|
|||
|
|
return False, f"Python语法错误: {str(e)}"
|
|||
|
|
|
|||
|
|
return True, ""
|