一、工具简介
🔍 沐歌字典格式化工具 - 您的数据转换与美化专家
一款基于 Python Flask 开发的在线工具,专为开发者、数据分析师和测试工程师设计,提供 JSON ↔ Python字典 的双向转换、格式化、压缩、查询等功能,让数据处理更高效、更直观!
✨ 核心功能亮点
✅ 智能识别:自动检测输入数据是 JSON 还是 Python字典,无需手动切换格式
✅ 极速转换:一键完成 JSON ↔ Python字典 互转,支持格式化、压缩
✅ 精准查询:内置 JSONPath 查询引擎,快速提取复杂结构数据
✅ 代码执行:安全执行 Python表达式,动态处理数据
✅ 语法高亮:美观的代码渲染,提升可读性
🎯 适用场景
开发者:调试API返回的JSON数据,转换为Python字典
测试工程师:验证数据结构,提取关键字段
数据分析师:清洗和预处理JSON数据集
教学演示:直观展示JSON与Python字典的对应关系
📌 无需安装,打开即用!
无论是日常开发还是临时调试,这款工具都能让您的数据处理事半功倍!
二、功能描述
- ✨这款工具主要提供以下核心功能:
功能类别 | 具体操作 | 说明 |
---|---|---|
格式化 | json格式化 | 将紧凑JSON转换为易读格式 |
格式化 | python字典格式化 | 美化Python字典结构 |
转换 | JSON ↔ Python字典 | 双向数据格式转换 |
压缩 | 数据压缩 | 去除所有空白字符 |
查询 | JSONPath查询 | 使用JSONPath表达式提取数据 |
执行 | Python代码执行 | 对输入数据执行Python表达式 |
三、技术架构
3.1、前端实现
3.1.1、数据展示区域
- 输入框支持多行编辑
- 输出区域带语法高亮
- 响应式布局适应不同屏幕
3.1.2、用户交互
- 一键复制功能
- 邮箱联系方式快速复制
- 操作结果即时反馈
3.1.3、视觉设计
- 简洁明了的按钮分组
- 操作状态颜色区分
- 友好的错误提示
3.1.4、前端代码
<!DOCTYPE html>
<html>
<head>
<title>沐歌字典格式化工具</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
line-height: 1.6;
padding: 0 15px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.editor-section {
margin-bottom: 20px;
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px;
background: #f9f9f9;
position: relative;
}
h3 {
margin-top: 0;
color: #333;
}
textarea {
width: 100%;
height: 200px;
font-family: monospace;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
resize: vertical;
box-sizing: border-box;
}
.button-row {
display: flex;
gap: 10px;
margin: 15px 0;
flex-wrap: wrap;
align-items: center;
}
button {
padding: 8px 15px;
cursor: pointer;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
transition: background 0.3s;
white-space: nowrap;
}
button:hover {
background: #45a049;
}
button.secondary {
background: #2196F3;
}
button.secondary:hover {
background: #0b7dda;
}
button.execute {
background: #ff9800;
}
button.execute:hover {
background: #e68a00;
}
.result-container {
margin-top: 20px;
}
.error {
color: red;
margin: 15px 0;
padding: 10px;
background: #ffeeee;
border-radius: 4px;
}
.info {
color: #31708f;
margin: 15px 0;
padding: 10px;
background: #d9edf7;
border-radius: 4px;
}
.output-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.copy-btn {
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>') no-repeat center;
background-size: 20px;
width: 36px;
height: 36px;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.copy-btn:hover {
background-color: #e0e0e0;
}
.contact-btn {
position: absolute;
top: 15px;
right: 15px;
width: 32px;
height: 32px;
border-radius: 50%;
background-color: #2196F3;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 16px;
transition: background-color 0.3s;
}
.contact-btn:hover {
background-color: #0b7dda;
}
.jsonpath-input {
flex-grow: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
min-width: 200px;
}
.execute-input {
flex-grow: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
min-width: 200px;
}
{{ pygments_css }}
</style>
</head>
<body>
<div class="container">
<h1 style="text-align: center;">沐歌字典格式化工具</h1>
<form method="post">
<!-- 输入区域 -->
<div class="editor-section">
<h3>输入:</h3>
<textarea name="dict_data" placeholder="输入Python字典或JSON数据,例如:\n\nDict:\n{'字符': 'string', '真': True, '假': False, '空': None}\n\nJSON:\n{'字符': 'string', '真': true, '假': false, '空': null}">{{ input_data }}</textarea>
<button type="button" class="contact-btn" onclick="copyEmail()">👤</button>
</div>
<!-- 操作按钮 -->
<div class="button-row">
<button type="submit" name="action" value="format_json">JSON 格式化</button>
<button type="submit" name="action" value="format_python">Python 格式化</button>
<button type="submit" name="action" value="minify">压缩</button>
<button type="submit" name="action" value="json_to_dict" class="secondary">JSON → Python字典</button>
<button type="submit" name="action" value="dict_to_json" class="secondary">Python字典 → JSON</button>
</div>
<!-- JSONPath查询 -->
<div class="button-row">
<input type="text" name="jsonpath_query" class="jsonpath-input"
placeholder="输入JSONPath表达式 (如: $.key, $[*].name)" value="{{ jsonpath_query }}">
<button type="submit" name="action" value="query_jsonpath" class="execute">执行查询</button>
</div>
<!-- 代码执行 -->
<div class="button-row">
<input type="text" name="execute_expr" class="execute-input"
placeholder="输入Python表达式 (如: data.get('key'))" value="{{ execute_expr }}">
<button type="submit" name="action" value="execute_code" class="execute">执行代码</button>
</div>
<!-- 输出区域 -->
<div class="editor-section">
<div class="output-header">
<h3>输出:</h3>
<button type="button" onclick="copyToClipboard()" class="copy-btn" title="复制"></button>
</div>
<textarea name="result_data" id="result_data">{{ result }}</textarea>
</div>
</form>
<!-- 格式化预览 -->
{% if formatted_result %}
<div class="result-container">
<h3>格式化预览:</h3>
<div id="formatted-result">{{ formatted_result|safe }}</div>
</div>
{% endif %}
{% if error %}
<div class="error">{{ error }}</div>
{% endif %}
{% if info %}
<div class="info">{{ info }}</div>
{% endif %}
</div>
<script>
function copyToClipboard() {
const result = document.getElementById('result_data');
result.select();
result.setSelectionRange(0, 99999);
try {
const successful = document.execCommand('copy');
const msg = successful ? '已复制到剪贴板!' : '复制失败';
alert(msg);
} catch (err) {
try {
navigator.clipboard.writeText(result.value).then(() => {
alert('已复制到剪贴板!');
}).catch(err => {
alert('复制失败,请手动选择文本后按Ctrl+C复制');
});
} catch (e) {
alert('复制失败,请手动选择文本后按Ctrl+C复制');
}
}
}
function copyEmail() {
const email = '229421064@qq.com';
const textarea = document.createElement('textarea');
textarea.value = email;
document.body.appendChild(textarea);
textarea.select();
try {
const successful = document.execCommand('copy');
if (successful) {
alert('已复制邮箱: ' + email);
} else {
throw new Error('Copy command failed');
}
} catch (err) {
try {
navigator.clipboard.writeText(email).then(() => {
alert('已复制邮箱: ' + email);
}).catch(err => {
alert('复制失败,请手动复制邮箱: ' + email);
});
} catch (e) {
alert('复制失败,请手动复制邮箱: ' + email);
}
}
document.body.removeChild(textarea);
}
</script>
</body>
</html>
3.2、后端实现
3.2.1、关键函数说明
- 数据格式化函数
def dict_to_pretty(data, indent=4):
"""递归格式化Python字典"""
if isinstance(data, dict):
items = []
for key, value in data.items():
items.append(f'{" "*indent}{repr(key)}: {dict_to_pretty(value, indent)}')
return "{\n" + ",\n".join(items) + "\n}"
elif isinstance(data, list):
items = [dict_to_pretty(item, indent) for item in data]
return "[\n" + ",\n".join(items) + "\n]"
else:
return repr(data)
- 输入类型检测
def detect_input_type(input_str):
"""自动检测输入是JSON还是Python字典"""
try:
json.loads(input_str)
return 'json'
except ValueError:
try:
parsed = ast.literal_eval(input_str)
if isinstance(parsed, (dict, list)):
return 'dict'
except (ValueError, SyntaxError):
pass
return None
3.2.2、后端代码
#!/usr/bin/python
# -*- coding: utf-8 -*-
from flask import Flask, render_template_string, request
import json
from pygments import highlight
from pygments.lexers import PythonLexer, JsonLexer
from pygments.formatters import HtmlFormatter
import ast
from collections import OrderedDict
from jsonpath import jsonpath # 使用jsonpath库
import traceback
app = Flask(__name__)
HTML_TEMPLATE = "html代码"
def dict_to_compact(data):
"""将字典转换为紧凑的Python格式字符串"""
if isinstance(data, dict):
items = []
for key, value in data.items():
key_str = repr(key)
value_str = dict_to_compact(value)
items.append(f"{key_str}:{value_str}")
return "{" + ",".join(items) + "}"
elif isinstance(data, list):
items = [dict_to_compact(item) for item in data]
return "[" + ",".join(items) + "]"
else:
return repr(data)
def dict_to_pretty(data, indent=4):
"""将字典转换为美观的Python格式字符串"""
if isinstance(data, dict):
items = []
for key, value in data.items():
key_str = repr(key)
value_str = dict_to_pretty(value, indent)
items.append(f'{" " * indent}{key_str}: {value_str}')
return "{\n" + ",\n".join(items) + "\n}"
elif isinstance(data, list):
items = []
for item in data:
items.append(f'{" " * indent}{dict_to_pretty(item, indent)}')
return "[\n" + ",\n".join(items) + "\n]"
else:
return repr(data)
def detect_input_type(input_str):
"""检测输入数据类型"""
input_str = input_str.strip()
if not input_str:
return None
# 尝试解析为JSON
try:
json.loads(input_str)
return 'json'
except ValueError:
pass
# 尝试解析为Python字典
try:
parsed = ast.literal_eval(input_str)
if isinstance(parsed, (dict, list)):
return 'dict'
except (ValueError, SyntaxError):
pass
return None
def parse_input(input_str, expected_type=None):
"""解析输入数据并验证类型"""
input_str = input_str.strip()
if not input_str:
return None, None
detected_type = detect_input_type(input_str)
if not detected_type:
return None, None
try:
if detected_type == 'json':
data = json.loads(input_str, object_pairs_hook=OrderedDict)
elif detected_type == 'dict':
data = ast.literal_eval(input_str)
if isinstance(data, dict):
data = OrderedDict(data)
elif not isinstance(data, list):
return None, None
else:
return None, None
if expected_type and detected_type != expected_type:
return None, None
return data, detected_type
except Exception:
return None, None
def minify_data(data, data_type):
"""压缩数据"""
if data_type == 'json':
return json.dumps(data, separators=(',', ':'), ensure_ascii=False)
elif data_type == 'dict':
return dict_to_compact(data)
else:
return None
@app.route('/', methods=['GET', 'POST'])
def index():
input_data = ""
result = ""
error = ""
info = ""
formatted_result = ""
jsonpath_query = ""
execute_expr = ""
pygments_css = HtmlFormatter().get_style_defs('.highlight')
if request.method == 'POST':
input_data = request.form.get('dict_data', '')
action = request.form.get('action', '')
jsonpath_query = request.form.get('jsonpath_query', '')
execute_expr = request.form.get('execute_expr', '')
try:
if not input_data.strip():
raise ValueError("请输入你要操作的数据")
if action == 'format_json':
data, data_type = parse_input(input_data, 'json')
if data is None:
raise ValueError("JSON格式化需要JSON格式输入")
result = json.dumps(data, indent=4, ensure_ascii=False, sort_keys=False)
formatted_result = highlight_code(result, 'json')
elif action == 'format_python':
data, data_type = parse_input(input_data, 'dict')
if data is None:
raise ValueError("Python格式化需要Python字典格式输入")
result = dict_to_pretty(data, indent=4)
formatted_result = highlight_code(result, 'python')
elif action == 'query_jsonpath':
data, data_type = parse_input(input_data)
if data is None:
raise ValueError("无法识别输入数据格式")
if not jsonpath_query:
raise ValueError("请输入JSONPath查询表达式")
try:
query_result = jsonpath(data, jsonpath_query)
if query_result is False: # jsonpath库在未找到时返回False
info = f"JSONPath未找到匹配项: {jsonpath_query}"
else:
result = dict_to_pretty(query_result, indent=4)
formatted_result = f"<h4>JSONPath查询结果 ({jsonpath_query}):</h4>{highlight_code(result, 'python')}"
info = f"JSONPath查询成功: {jsonpath_query}"
except Exception as e:
error = f"JSONPath查询错误: {str(e)}"
elif action == 'execute_code':
data, data_type = parse_input(input_data)
if data is None:
raise ValueError("无法识别输入数据格式")
if not execute_expr:
raise ValueError("请输入要执行的Python表达式")
try:
# 安全地执行代码,只允许访问data变量
locals_dict = {'data': data}
globals_dict = {}
exec(f"result_value = {execute_expr}", globals_dict, locals_dict)
result_value = locals_dict.get('result_value')
if isinstance(result_value, (dict, list)):
result = dict_to_pretty(result_value, indent=4)
else:
result = repr(result_value)
formatted_result = f"<h4>代码执行结果:</h4>{highlight_code(result, 'python')}"
info = f"代码执行成功: {execute_expr}"
except Exception as e:
error = f"代码执行错误: {str(e)}"
formatted_result = f"<div class='error'>{error}</div>"
elif action == 'minify':
output_data = request.form.get('result_data', '').strip()
if output_data:
output_data, output_type = parse_input(output_data)
if output_data is None:
raise ValueError("无法压缩输出内容,请先执行格式化操作")
result = minify_data(output_data, output_type)
else:
data, data_type = parse_input(input_data)
if data is None:
raise ValueError("无法识别输入数据格式")
result = minify_data(data, data_type)
if result is None:
raise ValueError("不支持压缩此类型数据")
formatted_result = highlight_code(result, 'json' if (
output_type if output_data else data_type) == 'json' else 'python')
elif action == 'json_to_dict':
data, data_type = parse_input(input_data, 'json')
if data is None:
raise ValueError("JSON转Python字典需要JSON格式输入")
result = dict_to_pretty(data, indent=4)
formatted_result = highlight_code(result, 'python')
info = "JSON → Python字典 转换完成"
elif action == 'dict_to_json':
data, data_type = parse_input(input_data, 'dict')
if data is None:
raise ValueError("Python字典转JSON需要Python字典格式输入")
result = json.dumps(data, indent=4, ensure_ascii=False, sort_keys=False)
formatted_result = highlight_code(result, 'json')
info = "Python字典 → JSON 转换完成"
else:
raise ValueError("无效的操作类型")
except ValueError as e:
error = str(e)
result = input_data
except Exception as e:
error = f"处理错误: {str(e)}"
result = input_data
traceback.print_exc()
return render_template_string(
HTML_TEMPLATE,
input_data=input_data,
result=result,
formatted_result=formatted_result,
error=error,
info=info,
jsonpath_query=jsonpath_query,
execute_expr=execute_expr,
pygments_css=pygments_css
)
def highlight_code(code, format_type):
"""高亮显示代码"""
if format_type == 'json':
lexer = JsonLexer()
else:
lexer = PythonLexer()
formatter = HtmlFormatter(style='colorful', noclasses=True)
return highlight(code, lexer, formatter)
if __name__ == '__main__':
app.run(debug=True, port=9999, host="0.0.0.0")