«

Python脚本-Unicode与中文互转工具

‎刘小猪 发布于 阅读:647 教程


Python脚本-Unicode与中文互转工具

import tkinter as tk
from tkinter import ttk, scrolledtext, filedialog, messagebox
import re

def unicode_to_chinese(unicode_str):
    """将Unicode编码转换为中文"""
    try:
        # 预处理:尝试提取所有可能的Unicode编码
        import re

        # 结果字符串
        result = ""

        # 使用正则表达式匹配多种Unicode编码格式
        # 1. \uXXXX 格式
        # 2. &#xXXXX; 格式
        # 3. U+XXXX 格式
        patterns = [
            r'\\u([0-9a-fA-F]{4})',           # \uXXXX
            r'&#x([0-9a-fA-F]{1,6});',        # &#xXXXX;
            r'[uU]\+([0-9a-fA-F]{4,6})'       # U+XXXX
        ]

        # 合并所有匹配项
        combined_pattern = '|'.join(patterns)
        matches = re.finditer(combined_pattern, unicode_str)
        last_end = 0
        found_match = False

        for match in matches:
            found_match = True
            # 添加匹配之前的非Unicode部分
            result += unicode_str[last_end:match.start()]

            # 确定匹配的是哪种格式
            if match.group(1):  # \uXXXX
                hex_code = match.group(1)
            elif match.group(2):  # &#xXXXX;
                hex_code = match.group(2)
            elif match.group(3):  # U+XXXX
                hex_code = match.group(3)
            else:
                continue

            try:
                char_code = int(hex_code, 16)
                if 0 <= char_code <= 0x10FFFF:  # 有效的Unicode范围
                    result += chr(char_code)
                else:
                    result += f"[无效Unicode:{hex_code}]"
            except (ValueError, OverflowError):
                result += f"[无法转换:{hex_code}]"

            last_end = match.end()

        # 添加最后一个匹配之后的部分
        result += unicode_str[last_end:]

        # 如果没有找到任何匹配,尝试使用原始方法
        if not found_match:
            # 使用原始的分割和处理方法作为备选
            # ... 原有代码逻辑 ...
            parts = []
            current_part = ""

            for char in unicode_str:
                if char.isalnum() or char in '\\uU':
                    current_part += char
                else:
                    if current_part:
                        parts.append(current_part)
                        current_part = ""
                    # 对于非字母数字和Unicode标识符的字符,直接添加到结果中
                    if char not in ' \t\n\r':
                        result += char

            if current_part:
                parts.append(current_part)

            result = ""  # 重置结果
            for part in parts:
                # 移除可能存在的'u'或'U'前缀和多余符号
                part = part.strip()
                if part.startswith(('\\u', '\\U')):
                    part = part[2:]  # 移除'\u'
                elif part.startswith(('u', 'U')):
                    part = part[1:]  # 移除'u'

                # 确保是有效的十六进制字符串
                try:
                    # 将十六进制转换为整数,然后转换为字符
                    if part and all(c in '0123456789abcdefABCDEF' for c in part):
                        # 添加长度检查,防止过大的值
                        if len(part) <= 8:  # 通常Unicode码点不会超过8位十六进制
                            char_code = int(part, 16)
                            # 添加范围检查,确保码点在有效范围内
                            if 0 <= char_code <= 0x10FFFF:  # Unicode的有效范围
                                result += chr(char_code)
                            else:
                                result += f"[无效Unicode:{part}]"
                        else:
                            result += f"[Unicode过长:{part}]"
                    elif part:  # 如果部分不是有效的十六进制,但不为空
                        result += part  # 直接添加到结果中
                except (ValueError, OverflowError):
                    # 如果转换失败,直接保留原始文本
                    result += f"[无法转换:{part}]"

        return result
    except Exception as e:
        return f"转换错误: {str(e)}"

def chinese_to_unicode(chinese_str, format_type="compact"):
    """将中文转换为Unicode编码,非中文字符保持原样"""
    try:
        result = ""
        for char in chinese_str:
            # 判断是否为中文字符
            # 中文字符的Unicode范围大致为:\u4e00-\u9fff
            if '\u4e00' <= char <= '\u9fff' or '\u3400' <= char <= '\u4dbf' or '\uf900' <= char <= '\ufaff':
                if format_type == "compact":
                    unicode_code = f"\\u{ord(char):04x}"
                    result += unicode_code
                elif format_type == "spaced":
                    unicode_code = f"\\u{ord(char):04x}"
                    result += unicode_code + " "
                elif format_type == "u_prefix":
                    unicode_code = f"U+{ord(char):04X}"
                    result += unicode_code + " "
                elif format_type == "html":
                    unicode_code = f"&#x{ord(char):04x};"
                    result += unicode_code
                else:  # 默认使用紧凑格式
                    unicode_code = f"\\u{ord(char):04x}"
                    result += unicode_code
            else:
                # 非中文字符保持原样
                result += char

        return result.strip()
    except Exception as e:
        return f"转换错误: {str(e)}"

# 批量处理函数
def batch_process(file_path, output_path, conversion_func, format_type=None):
    """批量处理文件"""
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()

        # 根据转换类型处理内容
        if conversion_func == unicode_to_chinese:
            result = unicode_to_chinese(content)
        else:
            result = chinese_to_unicode(content, format_type)

        # 写入输出文件
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(result)

        return True, f"处理完成,已保存到 {output_path}"
    except Exception as e:
        return False, f"处理失败: {str(e)}"

# 添加历史记录列表
history_records = []
max_history = 10  # 最大历史记录数量

def convert():
    """根据选择执行转换操作"""
    input_text = input_area.get("1.0", tk.END).strip()
    if not input_text:
        output_area.delete("1.0", tk.END)
        output_area.insert(tk.END, "请输入需要转换的文本")
        return

    conversion_type = conversion_var.get()
    if conversion_type == "Unicode转中文":
        result = unicode_to_chinese(input_text)
    else:  # 中文转Unicode
        format_type = format_var.get()  # 获取格式类型
        result = chinese_to_unicode(input_text, format_type)

    output_area.delete("1.0", tk.END)
    output_area.insert(tk.END, result)

    # 添加到历史记录
    add_to_history(conversion_type, input_text, result)
    update_history_display()

def add_to_history(conversion_type, input_text, result):
    """添加记录到历史列表"""
    # 添加时间戳
    import datetime
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    # 创建历史记录项 - 保存完整内容
    history_item = {
        "timestamp": timestamp,
        "type": conversion_type,
        "input": input_text,
        "output": result,
        "input_display": input_text[:47] + "..." if len(input_text) > 50 else input_text,
        "output_display": result[:47] + "..." if len(result) > 50 else result
    }

    # 添加到历史记录列表
    history_records.insert(0, history_item)  # 新记录插入到列表开头

    # 限制历史记录数量
    if len(history_records) > max_history:
        history_records.pop()  # 移除最旧的记录

def update_history_display():
    """更新历史记录显示"""
    history_listbox.delete(0, tk.END)  # 清空列表

    for item in history_records:
        # 使用截断后的显示文本
        display_text = f"[{item['timestamp']}] {item['type']}: {item['input_display']} → {item['output_display']}"
        history_listbox.insert(tk.END, display_text)

def on_history_select(event):
    """当用户选择历史记录时触发"""
    selection = history_listbox.curselection()
    if not selection:
        return

    # 获取选中的历史记录
    index = selection[0]
    if 0 <= index < len(history_records):
        selected_history = history_records[index]

        # 将历史记录的完整输入填充到输入区域
        input_area.delete("1.0", tk.END)
        input_area.insert(tk.END, selected_history["input"])

        # 将历史记录的完整输出填充到输出区域
        output_area.delete("1.0", tk.END)
        output_area.insert(tk.END, selected_history["output"])

        # 设置转换类型
        conversion_var.set(selected_history["type"])

def copy_to_clipboard():
    """复制输出结果到剪贴板"""
    result = output_area.get("1.0", tk.END).strip()
    root.clipboard_clear()
    root.clipboard_append(result)
    status_label.config(text="已复制到剪贴板")
    # 2秒后清除状态信息
    root.after(2000, lambda: status_label.config(text=""))

def clear_text():
    """清空输入和输出区域"""
    input_area.delete("1.0", tk.END)
    output_area.delete("1.0", tk.END)
    status_label.config(text="")

def open_batch_window():
    """打开批量处理窗口"""
    batch_window = tk.Toplevel(root)
    batch_window.title("批量处理")
    batch_window.geometry("500x300")
    batch_window.resizable(True, True)

    # 设置为模态窗口
    batch_window.transient(root)
    batch_window.grab_set()

    # 创建主框架
    batch_frame = ttk.Frame(batch_window, padding="10")
    batch_frame.pack(fill=tk.BOTH, expand=True)

    # 转换类型选择
    batch_conversion_var = tk.StringVar(value="Unicode转中文")
    conversion_frame = ttk.Frame(batch_frame)
    conversion_frame.pack(fill=tk.X, pady=5)

    ttk.Label(conversion_frame, text="转换类型:").pack(side=tk.LEFT)
    ttk.Radiobutton(conversion_frame, text="Unicode转中文", variable=batch_conversion_var, value="Unicode转中文").pack(side=tk.LEFT, padx=5)
    ttk.Radiobutton(conversion_frame, text="中文转Unicode", variable=batch_conversion_var, value="中文转Unicode").pack(side=tk.LEFT, padx=5)

    # 格式选择(仅在中文转Unicode时有效)
    batch_format_var = tk.StringVar(value="compact")
    format_frame = ttk.Frame(batch_frame)
    format_frame.pack(fill=tk.X, pady=5)

    ttk.Label(format_frame, text="Unicode格式:").pack(side=tk.LEFT)
    ttk.Radiobutton(format_frame, text="紧凑格式(\\uXXXX)", variable=batch_format_var, value="compact").pack(side=tk.LEFT, padx=5)
    ttk.Radiobutton(format_frame, text="空格分隔(\\uXXXX )", variable=batch_format_var, value="spaced").pack(side=tk.LEFT, padx=5)
    ttk.Radiobutton(format_frame, text="U+格式(U+XXXX)", variable=batch_format_var, value="u_prefix").pack(side=tk.LEFT, padx=5)
    ttk.Radiobutton(format_frame, text="HTML格式(&#xXXXX;)", variable=batch_format_var, value="html").pack(side=tk.LEFT, padx=5)

    # 文件选择
    file_frame = ttk.Frame(batch_frame)
    file_frame.pack(fill=tk.X, pady=5)

    input_file_var = tk.StringVar()
    ttk.Label(file_frame, text="输入文件:").pack(side=tk.LEFT)
    ttk.Entry(file_frame, textvariable=input_file_var, width=40).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

    def select_input_file():
        file_path = filedialog.askopenfilename(filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")])
        if file_path:
            input_file_var.set(file_path)
            # 自动设置输出文件路径
            if not output_file_var.get():
                import os
                base, ext = os.path.splitext(file_path)
                output_file_var.set(f"{base}_converted{ext}")

    ttk.Button(file_frame, text="浏览...", command=select_input_file).pack(side=tk.LEFT)

    # 输出文件
    output_frame = ttk.Frame(batch_frame)
    output_frame.pack(fill=tk.X, pady=5)

    output_file_var = tk.StringVar()
    ttk.Label(output_frame, text="输出文件:").pack(side=tk.LEFT)
    ttk.Entry(output_frame, textvariable=output_file_var, width=40).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

    def select_output_file():
        file_path = filedialog.asksaveasfilename(filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")])
        if file_path:
            output_file_var.set(file_path)

    ttk.Button(output_frame, text="浏览...", command=select_output_file).pack(side=tk.LEFT)

    # 处理按钮
    button_frame = ttk.Frame(batch_frame)
    button_frame.pack(fill=tk.X, pady=10)

    def start_batch_process():
        input_file = input_file_var.get()
        output_file = output_file_var.get()

        if not input_file or not output_file:
            messagebox.showerror("错误", "请选择输入和输出文件")
            return

        conversion_type = batch_conversion_var.get()
        if conversion_type == "Unicode转中文":
            success, message = batch_process(input_file, output_file, unicode_to_chinese)
        else:
            format_type = batch_format_var.get()
            success, message = batch_process(input_file, output_file, chinese_to_unicode, format_type)

        if success:
            messagebox.showinfo("成功", message)
            batch_window.destroy()
        else:
            messagebox.showerror("错误", message)

    ttk.Button(button_frame, text="开始处理", command=start_batch_process).pack(side=tk.LEFT, padx=5)
    ttk.Button(button_frame, text="取消", command=batch_window.destroy).pack(side=tk.LEFT, padx=5)

    # 状态标签
    status_label = ttk.Label(batch_frame, text="", foreground="green")
    status_label.pack(anchor=tk.W, pady=5)

# 创建主窗口
root = tk.Tk()
root.title("Unicode与中文互转工具")
root.geometry("800x600")  # 增加窗口大小
root.resizable(True, True)

# 设置样式
style = ttk.Style()
style.configure("TButton", padding=6, relief="flat", background="#ccc")
style.configure("TFrame", background="#f0f0f0")
style.configure("TLabelframe", background="#f0f0f0")
style.configure("TLabelframe.Label", background="#f0f0f0")

# 创建主框架
main_frame = ttk.Frame(root, padding="10")
main_frame.pack(fill=tk.BOTH, expand=True)

# 创建顶部工具栏
toolbar_frame = ttk.Frame(main_frame)
toolbar_frame.pack(fill=tk.X, pady=5)

# 转换类型选择
conversion_var = tk.StringVar(value="Unicode转中文")
ttk.Label(toolbar_frame, text="转换类型:").pack(side=tk.LEFT)
ttk.Radiobutton(toolbar_frame, text="Unicode转中文", variable=conversion_var, value="Unicode转中文").pack(side=tk.LEFT, padx=5)
ttk.Radiobutton(toolbar_frame, text="中文转Unicode", variable=conversion_var, value="中文转Unicode").pack(side=tk.LEFT, padx=5)

# 添加批量处理按钮
ttk.Button(toolbar_frame, text="批量处理", command=open_batch_window).pack(side=tk.RIGHT, padx=5)

# 格式选择
format_var = tk.StringVar(value="compact")
format_frame = ttk.Frame(main_frame)
format_frame.pack(fill=tk.X, pady=5)

ttk.Label(format_frame, text="Unicode格式:").pack(side=tk.LEFT)
ttk.Radiobutton(format_frame, text="紧凑格式(\\uXXXX)", variable=format_var, value="compact").pack(side=tk.LEFT, padx=5)
ttk.Radiobutton(format_frame, text="空格分隔(\\uXXXX )", variable=format_var, value="spaced").pack(side=tk.LEFT, padx=5)
ttk.Radiobutton(format_frame, text="U+格式(U+XXXX)", variable=format_var, value="u_prefix").pack(side=tk.LEFT, padx=5)
ttk.Radiobutton(format_frame, text="HTML格式(&#xXXXX;)", variable=format_var, value="html").pack(side=tk.LEFT, padx=5)

# 创建左右分栏
paned_window = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
paned_window.pack(fill=tk.BOTH, expand=True, pady=5)

# 左侧面板 - 输入和输出
left_panel = ttk.Frame(paned_window)
paned_window.add(left_panel, weight=2)

# 输入区域
input_frame = ttk.LabelFrame(left_panel, text="输入")
input_frame.pack(fill=tk.BOTH, expand=True, pady=5)

input_area = scrolledtext.ScrolledText(input_frame, wrap=tk.WORD, height=8)
input_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

# 按钮区域
button_frame = ttk.Frame(left_panel)
button_frame.pack(fill=tk.X, pady=5)

convert_button = ttk.Button(button_frame, text="转换", command=convert)
convert_button.pack(side=tk.LEFT, padx=5)

copy_button = ttk.Button(button_frame, text="复制结果", command=copy_to_clipboard)
copy_button.pack(side=tk.LEFT, padx=5)

clear_button = ttk.Button(button_frame, text="清空", command=clear_text)
clear_button.pack(side=tk.LEFT, padx=5)

# 输出区域
output_frame = ttk.LabelFrame(left_panel, text="输出")
output_frame.pack(fill=tk.BOTH, expand=True, pady=5)

output_area = scrolledtext.ScrolledText(output_frame, wrap=tk.WORD, height=8)
output_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

# 右侧面板 - 历史记录
right_panel = ttk.Frame(paned_window)
paned_window.add(right_panel, weight=1)

# 历史记录区域
history_frame = ttk.LabelFrame(right_panel, text="历史记录")
history_frame.pack(fill=tk.BOTH, expand=True, pady=5)

# 创建历史记录列表框和滚动条
history_scrollbar = ttk.Scrollbar(history_frame)
history_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

history_listbox = tk.Listbox(history_frame, yscrollcommand=history_scrollbar.set)
history_listbox.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
history_listbox.bind('<<ListboxSelect>>', on_history_select)

history_scrollbar.config(command=history_listbox.yview)

# 状态标签
status_label = ttk.Label(main_frame, text="", foreground="green")
status_label.pack(anchor=tk.W, pady=5)

# 启动应用
root.mainloop()

Python

收到2条评论
avatar
小欧 1 个月前
谢谢分享,正好需要
回复
commentator
刘小猪AI助手 1 个月前

感谢您的关注!很高兴这篇文章能帮到您。如果您在使用过程中遇到任何问题,欢迎随时交流。祝编码愉快!
回复