Python构建输入法应用

基于Python构建输入法应用是一个有趣的项目。下面我将为你提供一个完整的输入法应用设计方案,包含核心功能和实现代码。

设计思路

我将创建一个基于拼音的输入法,包含以下核心功能:

  • 拼音到汉字的转换

  • 候选词显示和选择

  • 用户界面

  • 词频调整和学习功能

项目结构

复制代码
input_method/
├── main.py              # 主程序入口
├── input_method.py      # 输入法核心类
├── pinyin_dict.py       # 拼音字典管理
├── ui.py                # 用户界面
├── data/
│   └── pinyin.txt       # 拼音-汉字映射数据
└── user_dict.py         # 用户词典管理

核心代码实现

1. 拼音字典管理 (pinyin_dict.py)

复制代码
import os
import re

class PinyinDict:
    def __init__(self, dict_file='data/pinyin.txt'):
        self.pinyin_map = {}
        self.load_dict(dict_file)
    
    def load_dict(self, dict_file):
        """加载拼音字典"""
        if not os.path.exists(dict_file):
            # 如果没有字典文件,创建基本字典
            self.create_basic_dict(dict_file)
        
        with open(dict_file, 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if not line or line.startswith('#'):
                    continue
                parts = line.split()
                if len(parts) >= 2:
                    pinyin = parts[0]
                    chars = parts[1:]
                    self.pinyin_map[pinyin] = chars
    
    def create_basic_dict(self, dict_file):
        """创建基本拼音字典"""
        # 确保目录存在
        os.makedirs(os.path.dirname(dict_file), exist_ok=True)
        
        # 简单的拼音-汉字映射示例
        basic_dict = {
            'ni': ['你', '泥', '尼', '拟', '逆'],
            'hao': ['好', '号', '豪', '浩', '耗'],
            'wo': ['我', '窝', '握', '沃', '卧'],
            'shi': ['是', '时', '十', '事', '市'],
            'jie': ['解', '接', '节', '界', '姐'],
            'mian': ['面', '免', '棉', '眠', '勉']
        }
        
        with open(dict_file, 'w', encoding='utf-8') as f:
            for pinyin, chars in basic_dict.items():
                f.write(f"{pinyin} {' '.join(chars)}\n")
    
    def get_chars(self, pinyin):
        """根据拼音获取对应的汉字列表"""
        return self.pinyin_map.get(pinyin, [])
    
    def is_valid_pinyin(self, pinyin):
        """检查是否是有效拼音"""
        # 简单的拼音格式检查
        return bool(re.match(r'^[a-z]+$', pinyin))

2. 用户词典管理 (user_dict.py)

复制代码
import json
import os

class UserDict:
    def __init__(self, user_dict_file='data/user_dict.json'):
        self.user_dict_file = user_dict_file
        self.user_dict = {}  # 格式: {"拼音": [("汉字", 词频), ...]}
        self.load_user_dict()
    
    def load_user_dict(self):
        """加载用户词典"""
        if os.path.exists(self.user_dict_file):
            try:
                with open(self.user_dict_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    # 转换格式
                    for pinyin, items in data.items():
                        self.user_dict[pinyin] = [(char, freq) for char, freq in items]
            except:
                self.user_dict = {}
    
    def save_user_dict(self):
        """保存用户词典"""
        # 确保目录存在
        os.makedirs(os.path.dirname(self.user_dict_file), exist_ok=True)
        
        # 转换为可JSON序列化的格式
        save_data = {}
        for pinyin, items in self.user_dict.items():
            save_data[pinyin] = [(char, freq) for char, freq in items]
        
        with open(self.user_dict_file, 'w', encoding='utf-8') as f:
            json.dump(save_data, f, ensure_ascii=False, indent=2)
    
    def add_word(self, pinyin, char):
        """添加用户词或更新词频"""
        if pinyin not in self.user_dict:
            self.user_dict[pinyin] = []
        
        # 查找是否已存在
        found = False
        for i, (c, freq) in enumerate(self.user_dict[pinyin]):
            if c == char:
                self.user_dict[pinyin][i] = (char, freq + 1)
                found = True
                break
        
        if not found:
            self.user_dict[pinyin].append((char, 1))
        
        # 按词频排序
        self.user_dict[pinyin].sort(key=lambda x: x[1], reverse=True)
        
        # 保存更改
        self.save_user_dict()
    
    def get_user_chars(self, pinyin):
        """获取用户词典中的汉字"""
        if pinyin in self.user_dict:
            return [char for char, freq in self.user_dict[pinyin]]
        return []

3. 输入法核心类 (input_method.py)

复制代码
import re
from pinyin_dict import PinyinDict
from user_dict import UserDict

class InputMethod:
    def __init__(self):
        self.pinyin_dict = PinyinDict()
        self.user_dict = UserDict()
        self.current_pinyin = ""
        self.candidates = []
        self.selected_index = 0
        self.page_size = 5
        self.current_page = 0
    
    def input_pinyin(self, pinyin_char):
        """输入拼音字符"""
        if pinyin_char.isalpha() and pinyin_char.islower():
            self.current_pinyin += pinyin_char
            self.update_candidates()
            return True
        return False
    
    def backspace(self):
        """删除最后一个拼音字符"""
        if self.current_pinyin:
            self.current_pinyin = self.current_pinyin[:-1]
            self.update_candidates()
            return True
        return False
    
    def update_candidates(self):
        """更新候选词列表"""
        if not self.current_pinyin:
            self.candidates = []
            self.current_page = 0
            return
        
        # 获取系统词典中的候选词
        system_candidates = self.pinyin_dict.get_chars(self.current_pinyin)
        
        # 获取用户词典中的候选词(优先显示)
        user_candidates = self.user_dict.get_user_chars(self.current_pinyin)
        
        # 合并候选词,用户词典的在前
        all_candidates = user_candidates + [c for c in system_candidates if c not in user_candidates]
        
        self.candidates = all_candidates
        self.current_page = 0
        self.selected_index = 0
    
    def get_current_candidates(self):
        """获取当前页的候选词"""
        start = self.current_page * self.page_size
        end = start + self.page_size
        return self.candidates[start:end]
    
    def next_page(self):
        """翻到下一页"""
        max_page = (len(self.candidates) - 1) // self.page_size
        if self.current_page < max_page:
            self.current_page += 1
            self.selected_index = 0
            return True
        return False
    
    def prev_page(self):
        """翻到上一页"""
        if self.current_page > 0:
            self.current_page -= 1
            self.selected_index = 0
            return True
        return False
    
    def select_candidate(self, index):
        """选择候选词"""
        current_candidates = self.get_current_candidates()
        if 0 <= index < len(current_candidates):
            selected_char = current_candidates[index]
            # 更新用户词典词频
            self.user_dict.add_word(self.current_pinyin, selected_char)
            # 清空当前拼音
            self.current_pinyin = ""
            self.candidates = []
            return selected_char
        return None
    
    def get_display_text(self):
        """获取显示文本"""
        return self.current_pinyin
    
    def has_candidates(self):
        """是否有候选词"""
        return len(self.candidates) > 0

4. 用户界面 (ui.py)

复制代码
import tkinter as tk
from tkinter import ttk

class InputMethodUI:
    def __init__(self, input_method):
        self.input_method = input_method
        self.root = tk.Tk()
        self.root.title("Python 输入法")
        self.root.geometry("400x200")
        self.root.configure(bg='lightgray')
        
        # 创建显示区域
        self.create_widgets()
        
        # 绑定键盘事件
        self.root.bind('<KeyPress>', self.on_key_press)
        
        # 设置窗口置顶
        self.root.attributes('-topmost', True)
    
    def create_widgets(self):
        """创建界面组件"""
        # 拼音显示区域
        self.pinyin_label = tk.Label(
            self.root, 
            text="", 
            font=("Arial", 16), 
            bg='white', 
            width=30, 
            anchor='w'
        )
        self.pinyin_label.pack(pady=10, padx=10, fill='x')
        
        # 候选词区域
        self.candidate_frame = tk.Frame(self.root, bg='lightgray')
        self.candidate_frame.pack(pady=5, padx=10, fill='x')
        
        self.candidate_buttons = []
        for i in range(5):  # 最多显示5个候选词
            btn = tk.Button(
                self.candidate_frame,
                text="",
                font=("Arial", 12),
                width=6,
                command=lambda idx=i: self.select_candidate(idx)
            )
            btn.grid(row=0, column=i, padx=2)
            self.candidate_buttons.append(btn)
        
        # 翻页按钮
        self.page_frame = tk.Frame(self.root, bg='lightgray')
        self.page_frame.pack(pady=5, padx=10, fill='x')
        
        self.prev_btn = tk.Button(
            self.page_frame,
            text="上一页",
            font=("Arial", 10),
            command=self.prev_page
        )
        self.prev_btn.pack(side='left', padx=5)
        
        self.next_btn = tk.Button(
            self.page_frame,
            text="下一页",
            font=("Arial", 10),
            command=self.next_page
        )
        self.next_btn.pack(side='left', padx=5)
        
        # 状态显示
        self.status_label = tk.Label(
            self.root,
            text="输入拼音,按空格选择,ESC清空",
            font=("Arial", 10),
            bg='lightgray'
        )
        self.status_label.pack(pady=5)
    
    def update_display(self):
        """更新显示"""
        # 更新拼音显示
        self.pinyin_label.config(text=self.input_method.get_display_text())
        
        # 更新候选词
        candidates = self.input_method.get_current_candidates()
        for i, btn in enumerate(self.candidate_buttons):
            if i < len(candidates):
                btn.config(text=f"{i+1}.{candidates[i]}")
                btn.config(state='normal')
            else:
                btn.config(text="")
                btn.config(state='disabled')
        
        # 更新翻页按钮状态
        self.prev_btn.config(state='normal' if self.input_method.current_page > 0 else 'disabled')
        max_page = (len(self.input_method.candidates) - 1) // self.input_method.page_size
        self.next_btn.config(state='normal' if self.input_method.current_page < max_page else 'disabled')
    
    def on_key_press(self, event):
        """处理键盘事件"""
        key = event.char
        
        if event.keysym == 'Escape':  # ESC键清空输入
            self.input_method.current_pinyin = ""
            self.input_method.candidates = []
        elif event.keysym == 'BackSpace':  # 退格键
            self.input_method.backspace()
        elif event.keysym == 'space':  # 空格键选择第一个候选词
            if self.input_method.has_candidates():
                selected = self.input_method.select_candidate(0)
                if selected:
                    print(f"选择了: {selected}")  # 实际应用中这里应该输出到目标程序
        elif key.isalpha() and key.islower():  # 拼音输入
            self.input_method.input_pinyin(key)
        elif key.isdigit() and key != '0':  # 数字键选择候选词
            idx = int(key) - 1
            if idx < len(self.input_method.get_current_candidates()):
                selected = self.input_method.select_candidate(idx)
                if selected:
                    print(f"选择了: {selected}")  # 实际应用中这里应该输出到目标程序
        
        self.update_display()
    
    def select_candidate(self, index):
        """选择候选词"""
        selected = self.input_method.select_candidate(index)
        if selected:
            print(f"选择了: {selected}")  # 实际应用中这里应该输出到目标程序
            self.update_display()
    
    def prev_page(self):
        """上一页"""
        if self.input_method.prev_page():
            self.update_display()
    
    def next_page(self):
        """下一页"""
        if self.input_method.next_page():
            self.update_display()
    
    def run(self):
        """运行界面"""
        self.update_display()
        self.root.mainloop()

5. 主程序 (main.py)

复制代码
from input_method import InputMethod
from ui import InputMethodUI

def main():
    # 创建输入法实例
    input_method = InputMethod()
    
    # 创建并运行界面
    ui = InputMethodUI(input_method)
    ui.run()

if __name__ == "__main__":
    main()
相关推荐
love530love38 分钟前
【笔记】ComfUI RIFEInterpolation 节点缺失问题(cupy CUDA 安装)解决方案
人工智能·windows·笔记·python·插件·comfyui
AI科技星1 小时前
为什么变化的电磁场才产生引力场?—— 统一场论揭示的时空动力学本质
数据结构·人工智能·经验分享·算法·计算机视觉
青瓷程序设计1 小时前
昆虫识别系统【最新版】Python+TensorFlow+Vue3+Django+人工智能+深度学习+卷积神经网络算法
人工智能·python·深度学习
咨询QQ276998851 小时前
V-REP小车项目+匹配文档,基于V-REP与MATLAB联合仿真,小车能够完成循迹、避障、走...
开发语言
咩图1 小时前
C#创建AI项目
开发语言·人工智能·c#
豆沙沙包?1 小时前
2025年--Lc293-784. 字母大小写全排列(回溯)--java版
java·开发语言
秋邱1 小时前
智启未来:AGI 教育融合 × 跨平台联盟 × 个性化空间,重构教育 AI 新范式开篇:一场 “教育 ×AI” 的范式革命
人工智能·python·重构·推荐算法·agi
爱吃泡芙的小白白2 小时前
vscode、anaconda、git、python配置安装(自用)
ide·git·vscode·python·anaconda·学习记录
谷隐凡二2 小时前
Kubernetes主从架构简单解析:基于Python的模拟实现
python·架构·kubernetes