Python检查JSON格式错误的多种方法

方法1:使用标准库json.loads()捕获异常(最常用)

python 复制代码
import json

def validate_json(json_str):
    """
    验证JSON字符串格式是否正确
    """
    try:
        json.loads(json_str)
        return True, None
    except json.JSONDecodeError as e:
        return False, e

# 使用示例
test_cases = [
    '{"name": "张三", "age": 25}',  # 正确
    '{"name": "张三", "age": 25',   # 缺少右括号
    "{'name': '张三'}",             # 单引号错误
    '{"name": "张三", "age": }',    # 缺少值
]

for i, json_str in enumerate(test_cases):
    is_valid, error = validate_json(json_str)
    print(f"\n测试 {i+1}: {repr(json_str[:50])}")
    if is_valid:
        print("✓ JSON格式正确")
    else:
        print(f"✗ JSON格式错误: {error.msg}")
        print(f"  位置: 第{error.lineno}行, 第{error.colno}列")
        print(f"  上下文: {repr(error.doc[max(0, error.pos-20):error.pos+20])}")

方法2:详细的JSON错误诊断工具

python 复制代码
import json
import re

class JSONValidator:
    """JSON格式验证器,提供详细错误信息"""
    
    @staticmethod
    def validate(json_str, verbose=True):
        """
        验证JSON并返回详细信息
        """
        errors = []
        
        # 检查1: 是否为空
        if not json_str or not json_str.strip():
            errors.append("JSON字符串为空")
            return False, errors
        
        # 检查2: 尝试解析
        try:
            data = json.loads(json_str)
            return True, ["JSON格式正确"]
        except json.JSONDecodeError as e:
            errors.append(f"解析错误: {e.msg}")
            errors.append(f"位置: 行{e.lineno}, 列{e.colno}")
            errors.append(f"字符位置: {e.pos}")
            
            # 显示错误上下文
            context_start = max(0, e.pos - 30)
            context_end = min(len(json_str), e.pos + 30)
            context = json_str[context_start:context_end]
            errors.append(f"上下文: ...{context}...")
            
            # 标记错误位置
            marker = ' ' * (e.pos - context_start) + '^'
            errors.append(f"标记:   {marker}")
            
            # 检查3: 常见格式问题
            if "'" in json_str and '"' not in json_str:
                errors.append("警告: 检测到单引号,JSON应使用双引号")
            
            if json_str.startswith("'") or json_str.startswith('"'):
                # 检查是否有BOM标记
                if json_str.startswith('\ufeff'):
                    errors.append("警告: 检测到BOM标记")
            
            # 检查4: 括号匹配
            bracket_stack = []
            for i, char in enumerate(json_str):
                if char in '{[(':
                    bracket_stack.append((char, i))
                elif char in '}])':
                    if not bracket_stack:
                        errors.append(f"错误: 位置{i}处有未匹配的闭合括号'{char}'")
                        break
                    opening, pos = bracket_stack.pop()
                    if (opening == '{' and char != '}') or \
                       (opening == '[' and char != ']') or \
                       (opening == '(' and char != ')'):
                        errors.append(f"错误: 位置{pos}的'{opening}'与位置{i}的'{char}'不匹配")
            
            if bracket_stack:
                for opening, pos in bracket_stack:
                    errors.append(f"错误: 位置{pos}的'{opening}'没有闭合")
            
            return False, errors
    
    @staticmethod
    def pretty_print_errors(json_str):
        """
        美观地打印JSON错误信息
        """
        is_valid, errors = JSONValidator.validate(json_str)
        
        print("=" * 60)
        print("JSON格式检查结果")
        print("=" * 60)
        print(f"输入: {repr(json_str[:100])}")
        print(f"状态: {'✓ 通过' if is_valid else '✗ 失败'}")
        print("-" * 60)
        
        for error in errors:
            print(f"  {error}")
        
        print("=" * 60)
        return is_valid

# 使用示例
if __name__ == "__main__":
    # 测试各种错误情况
    test_json = """
    {"name": "张三", "age": 25, "city": "北京"  # 缺少右括号
    """
    
    JSONValidator.pretty_print_errors(test_json)
    
    print("\n" + "=" * 60)
    print("测试正确的JSON")
    print("=" * 60)
    correct_json = '{"name": "张三", "age": 25, "city": "北京"}'
    JSONValidator.pretty_print_errors(correct_json)

方法3:逐行验证大JSON文件

python 复制代码
import json

def validate_json_file(filepath):
    """
    验证JSON文件格式
    """
    try:
        with open(filepath, 'r', encoding='utf-8') as f:
            content = f.read()
            json.loads(content)
        print(f"✓ {filepath} 格式正确")
        return True
    except json.JSONDecodeError as e:
        print(f"✗ {filepath} 格式错误:")
        print(f"  错误: {e.msg}")
        print(f"  位置: 行{e.lineno}, 列{e.colno}")
        
        # 显示错误行
        with open(filepath, 'r', encoding='utf-8') as f:
            lines = f.readlines()
            if e.lineno <= len(lines):
                print(f"  错误行: {e.lineno}: {lines[e.lineno-1].rstrip()}")
                # 标记错误位置
                marker = ' ' * (e.colno - 1) + '^'
                print(f"           {marker}")
        return False
    except FileNotFoundError:
        print(f"✗ 文件不存在: {filepath}")
        return False

# 使用示例
# validate_json_file('data.json')

方法4:使用jsonschema验证JSON结构

python 复制代码
import json
from jsonschema import validate, ValidationError, SchemaError

def validate_json_structure(json_str, schema=None):
    """
    验证JSON结构是否符合预期
    """
    try:
        data = json.loads(json_str)
    except json.JSONDecodeError as e:
        return False, f"JSON格式错误: {e.msg}"
    
    # 如果提供了schema,验证结构
    if schema:
        try:
            validate(instance=data, schema=schema)
            return True, "JSON结构正确"
        except ValidationError as e:
            return False, f"结构验证失败: {e.message}"
        except SchemaError as e:
            return False, f"Schema错误: {e.message}"
    
    return True, "JSON格式正确"

# 使用示例
schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "number"},
        "email": {"type": "string", "format": "email"}
    },
    "required": ["name", "age"]
}

json_str = '{"name": "张三", "age": 25, "email": "zhangsan@example.com"}'
is_valid, message = validate_json_structure(json_str, schema)
print(f"{message}: {is_valid}")

方法5:命令行工具方式

python 复制代码
# 保存为 validate_json.py
import json
import sys
import argparse

def main():
    parser = argparse.ArgumentParser(description='JSON格式验证工具')
    parser.add_argument('file', nargs='?', help='JSON文件路径')
    parser.add_argument('-s', '--string', help='JSON字符串')
    parser.add_argument('-v', '--verbose', action='store_true', help='详细输出')
    
    args = parser.parse_args()
    
    # 从文件或字符串读取
    if args.file:
        with open(args.file, 'r', encoding='utf-8') as f:
            json_str = f.read()
        source = f"文件: {args.file}"
    elif args.string:
        json_str = args.string
        source = "字符串"
    else:
        # 从stdin读取
        json_str = sys.stdin.read()
        source = "标准输入"
    
    # 验证
    try:
        data = json.loads(json_str)
        print(f"✓ {source}: JSON格式正确")
        if args.verbose:
            print(f"  类型: {type(data)}")
            if isinstance(data, dict):
                print(f"  键数量: {len(data)}")
            elif isinstance(data, list):
                print(f"  元素数量: {len(data)}")
        sys.exit(0)
    except json.JSONDecodeError as e:
        print(f"✗ {source}: JSON格式错误", file=sys.stderr)
        print(f"  错误: {e.msg}", file=sys.stderr)
        print(f"  位置: 行{e.lineno}, 列{e.colno}", file=sys.stderr)
        
        if args.verbose:
            # 显示上下文
            lines = json_str.split('\n')
            if e.lineno <= len(lines):
                print(f"\n  错误行 {e.lineno}:", file=sys.stderr)
                print(f"    {lines[e.lineno-1]}", file=sys.stderr)
                marker = ' ' * (e.colno - 1) + '^'
                print(f"    {marker}", file=sys.stderr)
        
        sys.exit(1)

if __name__ == '__main__':
    main()

使用方式:

bash 复制代码
# 验证文件
python validate_json.py data.json

# 验证字符串
python validate_json.py -s '{"name": "test"}'

# 详细模式
python validate_json.py -v data.json

# 从管道读取
echo '{"name": "test"}' | python validate_json.py

方法6:在线验证和格式化工具

如果不想写代码,可以使用这些工具:

方法7:使用IDE内置功能

VS Code:

  • 安装 "JSON" 相关扩展
  • .json 文件自动验证
  • 快捷键: Ctrl+Space 提示

PyCharm:

  • 内置JSON验证
  • 自动格式化: Ctrl+Alt+L
  • 语法高亮显示错误

实用调试技巧

python 复制代码
import json
import traceback

def debug_json_error(json_str):
    """
    调试JSON错误的实用函数
    """
    print("=" * 70)
    print("JSON调试信息")
    print("=" * 70)
    print(f"长度: {len(json_str)} 字符")
    print(f"前100字符: {repr(json_str[:100])}")
    print(f"后100字符: {repr(json_str[-100:])}")
    
    # 检查常见问题
    checks = [
        ("是否为空", lambda s: not s.strip()),
        ("是否以单引号开头", lambda s: s.strip().startswith("'")),
        ("是否包含单引号", lambda s: "'" in s and '"' not in s),
        ("是否有BOM标记", lambda s: s.startswith('\ufeff')),
        ("括号是否匹配", lambda s: s.count('{') != s.count('}') or s.count('[') != s.count(']')),
    ]
    
    print("\n初步检查:")
    for check_name, check_func in checks:
        result = check_func(json_str)
        status = "⚠ 可能有问题" if result else "✓ 正常"
        print(f"  {check_name}: {status}")
    
    # 尝试解析
    print("\n解析尝试:")
    try:
        data = json.loads(json_str)
        print(f"✓ 解析成功!")
        print(f"  类型: {type(data)}")
        if isinstance(data, dict):
            print(f"  键: {list(data.keys())[:5]}")
        return True
    except json.JSONDecodeError as e:
        print(f"✗ 解析失败!")
        print(f"  错误信息: {e.msg}")
        print(f"  位置: 行{e.lineno}, 列{e.colno}")
        
        # 显示详细上下文
        print(f"\n  错误位置上下文:")
        start = max(0, e.pos - 50)
        end = min(len(json_str), e.pos + 50)
        context = json_str[start:end]
        print(f"    ...{context}...")
        
        # 标记位置
        marker_pos = e.pos - start
        marker = ' ' * marker_pos + '^'
        print(f"    {' ' * (marker_pos)}{marker}")
        
        # 显示周围几行
        print(f"\n  周围行:")
        lines = json_str.split('\n')
        for i in range(max(0, e.lineno-2), min(len(lines), e.lineno+2)):
            prefix = "  > " if i == e.lineno-1 else "    "
            print(f"    {prefix}行{i+1}: {repr(lines[i][:100])}")
        
        return False
    finally:
        print("=" * 70)

# 使用示例
if __name__ == "__main__":
    # 测试有问题的JSON
    bad_json = '''
    {
        "name": "张三",
        'age': 25,  # 这里用了单引号
        "city": "北京"
    }
    '''
    
    debug_json_error(bad_json)

推荐方案总结

对于您的股票数据场景,建议使用:

python 复制代码
import json
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def safe_json_parse(data_str, source="未知来源"):
    """
    安全解析JSON,提供详细错误信息
    """
    try:
        return json.loads(data_str)
    except json.JSONDecodeError as e:
        logger.error(f"JSON解析失败 [{source}]:")
        logger.error(f"  错误: {e.msg}")
        logger.error(f"  位置: 行{e.lineno}, 列{e.colno}")
        logger.error(f"  上下文: {repr(data_str[max(0, e.pos-30):e.pos+30])}")
        
        # 尝试修复建议
        if "'" in data_str and '"' not in data_str:
            logger.warning("  建议: 检测到单引号,尝试使用 ast.literal_eval 或替换为双引号")
        
        raise

# 在您的代码中使用
try:
    data_dict = safe_json_parse(data_str, "Redis")
    # 处理数据...
except json.JSONDecodeError:
    # 记录错误并跳过或使用默认值
    logger.error("跳过无效数据")
    continue

这样可以快速定位和修复JSON格式问题!

相关推荐
chao-Cyril2 小时前
从入门到进阶:前端开发的成长之路与实战感悟
前端·javascript·vue.js
shalou29012 小时前
Spring 核心技术解析【纯干货版】- Ⅶ:Spring 切面编程模块 Spring-Instrument 模块精讲
前端·数据库·spring
Lightning-py2 小时前
ASCII,十进制,十六进制,八进制和二进制转换表
python
大时光2 小时前
js 封装 动画效果
前端
大时光2 小时前
html翻页时钟 效果
前端
大猫子的技术日记2 小时前
2025 AI Agent 开发实战指南:从上下文工程到多智能体协作
前端·人工智能·bootstrap
前端达人2 小时前
被JavaScript忽视的Web Animations API:为什么说它是前端动画的真正未来?
开发语言·前端·javascript·ecmascript
laplace01232 小时前
deque+yield+next语法
人工智能·笔记·python·agent·rag
忧郁的橙子.3 小时前
04-从零搭建本地AI对话系统:Ollama + DeepSeek-R1:7B + Streamlit
前端·chrome