1+ import tkinter as tk
2+ from tkinter import ttk , filedialog , messagebox
3+ import jieba
4+ from pypinyin import pinyin , Style
5+ import os
6+ import re
7+
8+ class ChineseToPinyinConverter :
9+ def __init__ (self ):
10+ # 只在类Unix系统上启用并行分词
11+ if os .name != 'nt' : # 如果不是Windows系统
12+ try :
13+ jieba .enable_parallel (4 )
14+ except :
15+ pass # 如果并行模式失败,继续使用单线程
16+
17+ def convert_text (self , text ):
18+ """将文本中的汉字转换为拼音,按词语组合,保留原始标点符号和格式"""
19+ try :
20+ # 使用正则表达式分割文本,保留所有非汉字字符
21+ pattern = re .compile (r'([\u4e00-\u9fff]+)|([^\u4e00-\u9fff]+)' )
22+ result = []
23+
24+ for match in pattern .finditer (text ):
25+ chinese_part , non_chinese_part = match .groups ()
26+
27+ if chinese_part :
28+ # 使用jieba进行分词
29+ words = jieba .cut (chinese_part , cut_all = False )
30+ pinyin_words = []
31+
32+ for word in words :
33+ # 只处理中文字符
34+ if any ('\u4e00 ' <= char <= '\u9fff ' for char in word ):
35+ # 获取带音标的拼音
36+ pinyin_list = pinyin (word , style = Style .TONE , heteronym = False )
37+ # 将词语的拼音连在一起,不带空格
38+ pinyin_str = '' .join ([item [0 ].lower () for item in pinyin_list ])
39+ pinyin_words .append (pinyin_str )
40+ else :
41+ # 非中文字符直接保留
42+ pinyin_words .append (word )
43+
44+ # 在词语之间添加空格
45+ result .append (' ' .join (pinyin_words ))
46+ elif non_chinese_part :
47+ # 保留所有非汉字字符(包括标点、时间戳等)
48+ result .append (non_chinese_part )
49+
50+ # 合并所有部分
51+ converted_text = '' .join (result )
52+
53+ # 修复:移除每行前后的多余空格
54+ lines = converted_text .split ('\n ' )
55+ cleaned_lines = [line .strip () for line in lines ]
56+ return '\n ' .join (cleaned_lines )
57+
58+ except Exception as e :
59+ raise Exception (f"转换过程中出错 (error): { str (e )} " )
60+
61+ class PinyinConverterApp :
62+ def __init__ (self , root ):
63+ self .root = root
64+ self .root .title ("C2PO: Chinese to Pinyin Offline 线下汉字转拼音工具" )
65+ self .root .geometry ("580x650" )
66+
67+ # 初始化转换器
68+ self .converter = ChineseToPinyinConverter ()
69+
70+ self .setup_ui ()
71+
72+ def setup_ui (self ):
73+ # 主框架
74+ main_frame = ttk .Frame (self .root , padding = "10" )
75+ main_frame .pack (fill = tk .BOTH , expand = True )
76+
77+ # 输入标签
78+ input_label = ttk .Label (main_frame , text = "Input (Chinese): 输入文本(中文):" )
79+ input_label .pack (anchor = tk .W , pady = (0 , 5 ))
80+
81+ # 输入文本框和滚动条
82+ input_frame = ttk .Frame (main_frame )
83+ input_frame .pack (fill = tk .BOTH , expand = True , pady = (0 , 10 ))
84+
85+ self .input_text = tk .Text (input_frame , height = 10 , wrap = tk .WORD )
86+ input_scrollbar = ttk .Scrollbar (input_frame , orient = tk .VERTICAL , command = self .input_text .yview )
87+ self .input_text .configure (yscrollcommand = input_scrollbar .set )
88+
89+ self .input_text .pack (side = tk .LEFT , fill = tk .BOTH , expand = True )
90+ input_scrollbar .pack (side = tk .RIGHT , fill = tk .Y )
91+
92+ # 按钮框架
93+ button_frame = ttk .Frame (main_frame )
94+ button_frame .pack (fill = tk .X , pady = 10 )
95+
96+ # 按钮
97+ ttk .Button (button_frame , text = "Import 导入文件" , command = self .import_file ).pack (side = tk .LEFT , padx = (0 , 10 ))
98+ ttk .Button (button_frame , text = "Convert 转换为拼音" , command = self .convert_text ).pack (side = tk .LEFT , padx = (0 , 10 ))
99+ ttk .Button (button_frame , text = "Copy 复制结果" , command = self .copy_to_clipboard ).pack (side = tk .LEFT , padx = (0 , 10 ))
100+ ttk .Button (button_frame , text = "Save Output 保存结果" , command = self .save_file ).pack (side = tk .LEFT , padx = (0 , 10 ))
101+ ttk .Button (button_frame , text = "Clear 清空" , command = self .clear_text ).pack (side = tk .LEFT )
102+
103+ # 输出标签
104+ output_label = ttk .Label (main_frame , text = "Output 拼音输出:" )
105+ output_label .pack (anchor = tk .W , pady = (10 , 5 ))
106+
107+ # 输出文本框和滚动条
108+ output_frame = ttk .Frame (main_frame )
109+ output_frame .pack (fill = tk .BOTH , expand = True )
110+
111+ self .output_text = tk .Text (output_frame , height = 10 , wrap = tk .WORD , state = tk .DISABLED )
112+ output_scrollbar = ttk .Scrollbar (output_frame , orient = tk .VERTICAL , command = self .output_text .yview )
113+ self .output_text .configure (yscrollcommand = output_scrollbar .set )
114+
115+ self .output_text .pack (side = tk .LEFT , fill = tk .BOTH , expand = True )
116+ output_scrollbar .pack (side = tk .RIGHT , fill = tk .Y )
117+
118+ # 状态栏
119+ self .status_var = tk .StringVar ()
120+ self .status_var .set ("Ready 就绪" )
121+ status_bar = ttk .Label (main_frame , textvariable = self .status_var , relief = tk .SUNKEN )
122+ status_bar .pack (fill = tk .X , pady = (10 , 0 ))
123+
124+ def import_file (self ):
125+ """Import 导入文件"""
126+ file_path = filedialog .askopenfilename (
127+ title = "Choose file 选择文件" ,
128+ filetypes = [("All files 所有文件" , "*.*" ), ("TXT file 文本文件" , "*.txt" ), ("SRT file SRT文件" , "*.srt" ), ("JSON file JSON文件" , "*.json" )]
129+ )
130+
131+ if file_path :
132+ try :
133+ # 尝试多种编码
134+ encodings = ['utf-8' , 'gbk' , 'gb2312' , 'utf-16' ]
135+ content = None
136+
137+ for encoding in encodings :
138+ try :
139+ with open (file_path , 'r' , encoding = encoding ) as file :
140+ content = file .read ()
141+ break
142+ except UnicodeDecodeError :
143+ continue
144+
145+ if content is None :
146+ messagebox .showerror ("Error 错误" , "Encoding error 无法读取文件,可能是编码问题" )
147+ return
148+
149+ self .input_text .delete (1.0 , tk .END )
150+ self .input_text .insert (1.0 , content )
151+ self .status_var .set (f"Imported 已导入文件: { os .path .basename (file_path )} " )
152+
153+ except Exception as e :
154+ messagebox .showerror ("Error 错误" , f"Error while reading: 读取文件时出错: { str (e )} " )
155+ self .status_var .set ("Import failed! 导入文件失败" )
156+
157+ def convert_text (self ):
158+ """转换文本为拼音"""
159+ input_content = self .input_text .get (1.0 , tk .END ).strip ()
160+
161+ if not input_content :
162+ messagebox .showwarning ("Warning 警告" , "Nothing to convert 请输入要转换的中文文本" )
163+ return
164+
165+ try :
166+ self .status_var .set ("Converting 正在转换..." )
167+ self .root .update_idletasks () # 强制更新UI
168+
169+ # 转换文本
170+ pinyin_content = self .converter .convert_text (input_content )
171+
172+ # 更新输出文本框
173+ self .output_text .config (state = tk .NORMAL )
174+ self .output_text .delete (1.0 , tk .END )
175+ self .output_text .insert (1.0 , pinyin_content )
176+ self .output_text .config (state = tk .DISABLED )
177+
178+ self .status_var .set ("Conversion complete 转换完成" )
179+
180+ except Exception as e :
181+ messagebox .showerror ("Error 错误" , str (e ))
182+ self .status_var .set ("Conversion failed 转换失败" )
183+
184+ def copy_to_clipboard (self ):
185+ """Copy to clipboard 复制结果到剪贴板"""
186+ output_content = self .output_text .get (1.0 , tk .END ).strip ()
187+
188+ if not output_content :
189+ messagebox .showwarning ("Warning 警告" , "Nothing to copy 没有内容可复制" )
190+ return
191+
192+ try :
193+ # 清空剪贴板并添加新内容
194+ self .root .clipboard_clear ()
195+ self .root .clipboard_append (output_content )
196+ # 确保剪贴板内容在程序退出后仍然可用
197+ self .root .update ()
198+
199+ self .status_var .set ("Copied to clipboard 已复制到剪贴板" )
200+ messagebox .showinfo ("Success 成功" , "Content has been copied to clipboard! 内容已复制到剪贴板!" )
201+
202+ except Exception as e :
203+ messagebox .showerror ("Error 错误" , f"Error while copying to clipboard: 复制到剪贴板时出错: { str (e )} " )
204+ self .status_var .set ("Copy failed 复制失败" )
205+
206+ def save_file (self ):
207+ """Save output to file 保存结果到文件"""
208+ output_content = self .output_text .get (1.0 , tk .END ).strip ()
209+
210+ if not output_content :
211+ messagebox .showwarning ("Error 警告" , "Nothing to save \n 没有内容可保存" )
212+ return
213+
214+ file_path = filedialog .asksaveasfilename (
215+ title = "Save file 保存文件" ,
216+ defaultextension = ".txt" ,
217+ filetypes = [("TXT file 文本文件" , "*.txt" ), ("All files 所有文件" , "*.*" )]
218+ )
219+
220+ if file_path :
221+ try :
222+ with open (file_path , 'w' , encoding = 'utf-8' ) as file :
223+ file .write (output_content )
224+
225+ self .status_var .set (f"File saved as 文件已保存: { os .path .basename (file_path )} " )
226+ messagebox .showinfo ("Success 成功" , "File saved 文件保存成功!" )
227+
228+ except Exception as e :
229+ messagebox .showerror ("Error 错误" , f"Error while saving 保存文件时出错: { str (e )} " )
230+ self .status_var .set ("Saving failed 保存失败" )
231+
232+ def clear_text (self ):
233+ """Clear all text 清空所有文本"""
234+ self .input_text .delete (1.0 , tk .END )
235+ self .output_text .config (state = tk .NORMAL )
236+ self .output_text .delete (1.0 , tk .END )
237+ self .output_text .config (state = tk .DISABLED )
238+ self .status_var .set ("Cleared 已清空" )
239+
240+ def main ():
241+ # 检查依赖
242+ try :
243+ import jieba
244+ from pypinyin import pinyin , Style
245+ except ImportError as e :
246+ print ("Missing package, please install: 缺少必要的依赖库,请安装:" )
247+ print ("pip install jieba pypinyin" )
248+ return
249+
250+ # 创建主窗口
251+ root = tk .Tk ()
252+ app = PinyinConverterApp (root )
253+
254+ # 添加测试文本
255+ test_text = """此处可填需要转拼音的汉字内容"""
256+
257+ app .input_text .insert (1.0 , test_text )
258+
259+ root .mainloop ()
260+
261+ if __name__ == "__main__" :
262+ main ()
0 commit comments