最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Python+PyQt5實(shí)現(xiàn)漢字轉(zhuǎn)拼音的智能轉(zhuǎn)換工具

 更新時(shí)間:2026年03月11日 09:29:56   作者:創(chuàng)客白澤  
在中文自然語(yǔ)言處理和學(xué)習(xí)中,漢字轉(zhuǎn)拼音是一個(gè)基礎(chǔ)但至關(guān)重要的功能,本文將詳細(xì)介紹如何使用Python開(kāi)發(fā)一個(gè)功能全面的漢字轉(zhuǎn)拼音工具,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下

概述

在中文自然語(yǔ)言處理和學(xué)習(xí)中,漢字轉(zhuǎn)拼音是一個(gè)基礎(chǔ)但至關(guān)重要的功能。本文將詳細(xì)介紹如何使用Python開(kāi)發(fā)一個(gè)功能全面的漢字轉(zhuǎn)拼音工具,該工具不僅支持多種拼音風(fēng)格轉(zhuǎn)換,還集成了文本朗讀、批量文件處理等實(shí)用功能。

功能亮點(diǎn)

多風(fēng)格拼音轉(zhuǎn)換

  • 普通拼音(不帶聲調(diào))
  • 帶聲調(diào)拼音(符號(hào)標(biāo)注)
  • 數(shù)字標(biāo)注聲調(diào)
  • 聲調(diào)在拼音后顯示

高級(jí)功能

  • 標(biāo)點(diǎn)符號(hào)智能處理(保留/刪除)
  • 文本朗讀功能(支持多語(yǔ)言)
  • 批量文件轉(zhuǎn)換處理
  • 實(shí)時(shí)進(jìn)度顯示

用戶體驗(yàn)

  • 美觀的PyQt5界面
  • 響應(yīng)式設(shè)計(jì)
  • 操作歷史記錄
  • 一鍵復(fù)制結(jié)果

界面展示

主界面

開(kāi)發(fā)步驟詳解

1. 環(huán)境準(zhǔn)備

pip install PyQt5 pypinyin gTTS pygame pydantic

2. 核心架構(gòu)設(shè)計(jì)

工具采用MVC架構(gòu):

  • ModelPinyinConverterTTSEngine
  • View:PyQt5界面
  • Controller:主窗口事件處理

3. 拼音轉(zhuǎn)換核心實(shí)現(xiàn)

class PinyinConverter:
    def __init__(self, text):
        self.text = text

    def replace(self):
        """中文標(biāo)點(diǎn)轉(zhuǎn)英文標(biāo)點(diǎn)"""
        replace_map = str.maketrans('。,???;:"”‘'', '.,!?;:""\'\'')
        self.text = self.text.translate(replace_map)

    def out_pinyin(self, style=Style.NORMAL):
        """帶聲調(diào)拼音輸出"""
        return ' '.join([item for sublist in 
                       pinyin(self.text, style=style) 
                       for item in sublist])

4. 多線程文件處理

class FileConverterThread(QThread):
    progress_signal = pyqtSignal(int)
    finished_signal = pygitSignal(list)

    def run(self):
        for i, file in enumerate(self.files):
            # 處理邏輯...
            self.progress_signal.emit(progress)
        self.finished_signal.emit(results)

5. 語(yǔ)音合成引擎

class TTSEngine:
    def speak(self, text, lang='zh'):
        tts = gTTS(text=text, lang=lang)
        with tempfile.NamedTemporaryFile() as f:
            tts.save(f.name)
            pygame.mixer.music.load(f.name)
            pygame.mixer.music.play()

關(guān)鍵代碼解析

1. 拼音風(fēng)格映射

self.style_mapping = {
    0: ("normal", Style.NORMAL),  # 普通
    1: ("tone", Style.TONE),      # 帶聲調(diào)
    2: ("tone2", Style.TONE2),    # 數(shù)字聲調(diào)
    3: ("tone3", Style.TONE3)    # 聲調(diào)在后
}

2. 響應(yīng)式UI設(shè)計(jì)

def init_ui(self):
    main_layout = QVBoxLayout()
    
    # 輸入?yún)^(qū)域
    input_group = QGroupBox("輸入漢字")
    self.input_text = QTextEdit()
    
    # 選項(xiàng)區(qū)域
    options_group = QGroupBox("轉(zhuǎn)換選項(xiàng)")
    self.style_group = QButtonGroup()
    
    # 將組件添加到布局...

3. 文件批量處理流程

源碼下載

from typing import List, Union
from pydantic import BaseModel
from pypinyin import pinyin, lazy_pinyin, Style
import re
import os
import tempfile
import pygame
from gtts import gTTS
import sys
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QTextEdit, QLabel, QRadioButton, QButtonGroup, QCheckBox,
    QPushButton, QFrame, QMessageBox, QFileDialog, QComboBox,
    QProgressBar, QGroupBox, QLineEdit, QSlider, QSizePolicy
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QIcon, QFont


class TTSEngine:
    """高質(zhì)量的TTS引擎封裝"""
    def __init__(self):
        pygame.mixer.init()
        self.temp_files = []
        
    def speak(self, text, lang='zh'):
        try:
            # 創(chuàng)建臨時(shí)音頻文件
            with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as f:
                temp_file = f.name
            
            # 使用gTTS生成語(yǔ)音
            tts = gTTS(text=text, lang=lang, slow=False)
            tts.save(temp_file)
            self.temp_files.append(temp_file)
            
            # 播放音頻
            pygame.mixer.music.load(temp_file)
            pygame.mixer.music.play()
            
            # 等待播放完成
            while pygame.mixer.music.get_busy():
                pygame.time.Clock().tick(10)
                
        except Exception as e:
            raise Exception(f"語(yǔ)音合成失敗: {str(e)}")
            
    def cleanup(self):
        """清理臨時(shí)文件"""
        for f in self.temp_files:
            try:
                os.unlink(f)
            except:
                pass
        self.temp_files = []
        pygame.mixer.quit()


class FileConverterThread(QThread):
    """文件批量轉(zhuǎn)換線程"""
    progress_signal = pyqtSignal(int)
    finished_signal = pyqtSignal(list)
    error_signal = pyqtSignal(str)

    def __init__(self, files, style, keep_punct):
        super().__init__()
        self.files = files
        self.style = style
        self.keep_punct = keep_punct
        self.running = True

    def run(self):
        results = []
        total_files = len(self.files)
        
        style_map = {
            "normal": Style.NORMAL,
            "tone": Style.TONE,
            "tone2": Style.TONE2,
            "tone3": Style.TONE3
        }
        style = style_map.get(self.style, Style.NORMAL)

        for i, file_path in enumerate(self.files):
            if not self.running:
                break

            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()

                converter = PinyinConverter(content)
                
                if self.keep_punct:
                    converter.replace()
                    result = converter.out_pinyin(style=style)
                else:
                    converter.del_biandian()
                    result = converter.out_lazy_pinyin(style=style)

                # 保存結(jié)果到新文件
                base, ext = os.path.splitext(file_path)
                output_path = f"{base}_pinyin{ext}"
                with open(output_path, 'w', encoding='utf-8') as f:
                    f.write(result)

                results.append((file_path, output_path))
                self.progress_signal.emit(int((i + 1) / total_files * 100))

            except Exception as e:
                self.error_signal.emit(f"處理文件 {os.path.basename(file_path)} 時(shí)出錯(cuò): {str(e)}")

        self.finished_signal.emit(results)

    def stop(self):
        self.running = False


class TextRequest(BaseModel):
    text: Union[str, List[str]]
    style: str = "normal"
    keep_punctuation: bool = False


class PinyinConverter:
    def __init__(self, text):
        self.text = text

    def replace(self):
        """替換中文標(biāo)點(diǎn)為英文標(biāo)點(diǎn)"""
        replace_map = str.maketrans('。,?。?;:"”‘'', '.,!?;:""\'\'')
        if isinstance(self.text, str):
            self.text = self.text.translate(replace_map)
            self.text = re.sub(r'\s+', ' ', self.text).strip()
        elif isinstance(self.text, list):
            cleaned = []
            for item in self.text:
                if isinstance(item, str):
                    item = item.translate(replace_map)
                    item = re.sub(r'\s+', ' ', item).strip()
                    if item:
                        cleaned.append(item)
            self.text = ' '.join(cleaned)
        else:
            raise TypeError("Unsupported type for self.text. Expected str or list.")

    def del_biandian(self):
        """刪除所有標(biāo)點(diǎn)符號(hào)"""
        self.text = re.sub(r'[^\w\s]', '', self.text)
        self.text = re.sub(r'\s+', ' ', self.text).strip()

    def out_lazy_pinyin(self, style=Style.NORMAL):
        """輸出不帶聲調(diào)的拼音"""
        pinyin_list = lazy_pinyin(hans=self.text, style=style, v_to_u=True)
        filtered = [p for p in pinyin_list if p.strip()]
        return ' '.join(filtered)

    def out_pinyin(self, style=Style.NORMAL):
        """輸出帶聲調(diào)的拼音"""
        pinyin_date = pinyin(hans=self.text, style=style, v_to_u=True)
        pinyin_date_flat = [item for sublist in pinyin_date for item in sublist]
        filtered = [p for p in pinyin_date_flat if p.strip()]
        return ' '.join(filtered)


class PinyinConverterApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("漢字轉(zhuǎn)拼音工具 ?????? (增強(qiáng)版)")
        self.setGeometry(100, 100, 900, 800)  # 稍微增大窗口尺寸
        
        # 初始化TTS引擎
        self.tts_engine = TTSEngine()
        
        # 樣式設(shè)置
        self.setup_styles()
        self.style_mapping = {
            0: ("normal", Style.NORMAL),
            1: ("tone", Style.TONE),
            2: ("tone2", Style.TONE2),
            3: ("tone3", Style.TONE3)
        }
        
        self.init_ui()
        
    def setup_styles(self):
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f5f5f5;
            }
            QLabel {
                font-size: 14px;
            }
            QTextEdit, QLineEdit {
                border: 1px solid #ccc;
                border-radius: 4px;
                padding: 5px;
                font-size: 14px;
                background-color: white;
            }
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                padding: 8px 16px;
                text-align: center;
                text-decoration: none;
                font-size: 14px;
                margin: 4px 2px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton#copyBtn {
                background-color: #2196F3;
            }
            QPushButton#copyBtn:hover {
                background-color: #0b7dda;
            }
            QPushButton#clearBtn {
                background-color: #ff9800;
            }
            QPushButton#clearBtn:hover {
                background-color: #e68a00;
            }
            QPushButton#exitBtn {
                background-color: #f44336;
            }
            QPushButton#exitBtn:hover {
                background-color: #da190b;
            }
            QPushButton#speakBtn {
                background-color: #9c27b0;
            }
            QPushButton#speakBtn:hover {
                background-color: #7b1fa2;
            }
            QGroupBox {
                border: 1px solid #ddd;
                border-radius: 5px;
                margin-top: 10px;
                font-size: 14px;
                padding-top: 15px;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
                padding: 0 3px;
            }
            QRadioButton, QCheckBox {
                font-size: 14px;
                spacing: 5px;
            }
            QProgressBar {
                border: 1px solid #ccc;
                border-radius: 3px;
                text-align: center;
            }
            QProgressBar::chunk {
                background-color: #4CAF50;
                width: 10px;
            }
            QSlider::groove:horizontal {
                height: 8px;
                background: #ddd;
                border-radius: 4px;
            }
            QSlider::handle:horizontal {
                width: 18px;
                height: 18px;
                margin: -5px 0;
                background: #4CAF50;
                border-radius: 9px;
            }
            QSlider::sub-page:horizontal {
                background: #4CAF50;
                border-radius: 4px;
            }
            QComboBox {
                padding: 3px;
                border: 1px solid #ccc;
                border-radius: 4px;
                min-width: 100px;
            }
        """)
        
    def init_ui(self):
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局使用垂直布局
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(15, 15, 15, 15)
        main_layout.setSpacing(15)
        
        # 輸入?yún)^(qū)域
        input_group = self.create_input_group()
        main_layout.addWidget(input_group)
        
        # 選項(xiàng)區(qū)域 - 使用水平布局將選項(xiàng)和發(fā)音設(shè)置并排放置
        options_row = QHBoxLayout()
        options_row.setSpacing(15)
        
        # 轉(zhuǎn)換選項(xiàng)
        options_group = self.create_options_group()
        options_row.addWidget(options_group, stretch=1)
        
        # 發(fā)音選項(xiàng)
        speech_group = self.create_speech_options()
        options_row.addWidget(speech_group, stretch=1)
        
        main_layout.addLayout(options_row)
        
        # 文件處理區(qū)域
        file_group = self.create_file_group()
        main_layout.addWidget(file_group)
        
        # 按鈕區(qū)域 - 將三個(gè)按鈕放在同一水平線上
        button_row = QHBoxLayout()
        button_row.setSpacing(15)
        
        # 轉(zhuǎn)換為拼音按鈕
        self.convert_btn = QPushButton("轉(zhuǎn)換為拼音 ??")
        self.convert_btn.clicked.connect(self.convert_text)
        self.convert_btn.setStyleSheet("font-size: 16px; padding: 10px 20px;")
        button_row.addWidget(self.convert_btn)
        
        # 批量轉(zhuǎn)換文件按鈕
        self.convert_file_btn = QPushButton("批量轉(zhuǎn)換文件")
        self.convert_file_btn.clicked.connect(self.start_file_conversion)
        self.convert_file_btn.setStyleSheet("font-size: 16px; padding: 10px 20px;")
        button_row.addWidget(self.convert_file_btn)
        
        # 停止轉(zhuǎn)換按鈕
        self.stop_btn = QPushButton("停止轉(zhuǎn)換")
        self.stop_btn.clicked.connect(self.stop_file_conversion)
        self.stop_btn.setEnabled(False)
        self.stop_btn.setStyleSheet("font-size: 16px; padding: 10px 20px;")
        button_row.addWidget(self.stop_btn)
        
        # 添加彈性空間使按鈕居中
        button_row.addStretch()
        main_layout.addLayout(button_row)
        
        # 輸出區(qū)域
        output_group = self.create_output_group()
        main_layout.addWidget(output_group)
        
        # 進(jìn)度條
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        main_layout.addWidget(self.progress_bar)
        
        # 底部按鈕
        button_frame = self.create_button_frame()
        main_layout.addWidget(button_frame)
        
        # 設(shè)置布局比例
        main_layout.setStretch(0, 2)  # 輸入?yún)^(qū)域
        main_layout.setStretch(1, 1)  # 選項(xiàng)區(qū)域
        main_layout.setStretch(2, 1)  # 文件區(qū)域
        main_layout.setStretch(3, 0)  # 按鈕區(qū)域
        main_layout.setStretch(4, 2)  # 輸出區(qū)域
        main_layout.setStretch(5, 0)  # 進(jìn)度條
        main_layout.setStretch(6, 0)  # 底部按鈕
        
    def create_input_group(self):
        """創(chuàng)建輸入?yún)^(qū)域"""
        group = QGroupBox("輸入漢字 ??")
        layout = QVBoxLayout(group)
        
        self.input_text = QTextEdit()
        self.input_text.setPlaceholderText("請(qǐng)輸入要轉(zhuǎn)換的漢字內(nèi)容...")
        self.input_text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        layout.addWidget(self.input_text)
        
        return group
        
    def create_options_group(self):
        """創(chuàng)建轉(zhuǎn)換選項(xiàng)區(qū)域"""
        group = QGroupBox("轉(zhuǎn)換選項(xiàng) ??")
        layout = QVBoxLayout(group)
        
        # 拼音風(fēng)格選擇
        style_label = QLabel("拼音風(fēng)格:")
        style_label.setStyleSheet("font-weight: bold;")
        layout.addWidget(style_label)
        
        self.style_group = QButtonGroup()
        
        styles = [
            ("普通 (不帶聲調(diào)) ??", 0),
            ("帶聲調(diào) ??", 1),
            ("數(shù)字聲調(diào) ??", 2),
            ("聲調(diào)在拼音后 ??", 3)
        ]
        
        for text, value in styles:
            rb = QRadioButton(text)
            rb.setStyleSheet("font-size: 14px;")
            self.style_group.addButton(rb, value)
            layout.addWidget(rb)
            if value == 0:
                rb.setChecked(True)
        
        # 標(biāo)點(diǎn)符號(hào)選項(xiàng)
        self.punctuation_cb = QCheckBox("保留標(biāo)點(diǎn)符號(hào) ??")
        self.punctuation_cb.setStyleSheet("font-size: 14px;")
        layout.addWidget(self.punctuation_cb)
        
        return group
        
    def create_speech_options(self):
        """創(chuàng)建發(fā)音選項(xiàng)面板"""
        group = QGroupBox("發(fā)音選項(xiàng) ??")
        layout = QVBoxLayout(group)
        
        # 語(yǔ)言選擇
        lang_layout = QHBoxLayout()
        lang_layout.addWidget(QLabel("語(yǔ)言:"))
        
        self.lang_combo = QComboBox()
        self.lang_combo.addItem("普通話", "zh")
        self.lang_combo.addItem("粵語(yǔ)", "zh-yue")
        self.lang_combo.addItem("英語(yǔ)", "en")
        lang_layout.addWidget(self.lang_combo, stretch=1)
        
        layout.addLayout(lang_layout)
        
        # 語(yǔ)速調(diào)節(jié)
        speed_layout = QVBoxLayout()
        speed_layout.addWidget(QLabel("語(yǔ)速:"))
        
        self.speed_slider = QSlider(Qt.Horizontal)
        self.speed_slider.setRange(50, 200)
        self.speed_slider.setValue(100)
        self.speed_slider.setTickInterval(10)
        self.speed_slider.setTickPosition(QSlider.TicksBelow)
        
        speed_value_layout = QHBoxLayout()
        speed_value_layout.addWidget(QLabel("慢"))
        speed_value_layout.addWidget(self.speed_slider)
        speed_value_layout.addWidget(QLabel("快"))
        
        self.speed_label = QLabel("100%")
        self.speed_label.setAlignment(Qt.AlignCenter)
        
        speed_layout.addLayout(speed_value_layout)
        speed_layout.addWidget(self.speed_label)
        
        # 連接信號(hào)
        self.speed_slider.valueChanged.connect(
            lambda v: self.speed_label.setText(f"{v}%"))
        
        layout.addLayout(speed_layout)
        
        return group
        
    def create_file_group(self):
        """創(chuàng)建文件處理區(qū)域"""
        group = QGroupBox("文件批量處理 ??")
        layout = QVBoxLayout(group)
        
        # 文件選擇
        file_select_layout = QHBoxLayout()
        self.file_path_edit = QLineEdit()
        self.file_path_edit.setPlaceholderText("選擇或拖放文件到此...")
        self.file_path_edit.setReadOnly(True)
        
        browse_btn = QPushButton("選擇文件")
        browse_btn.clicked.connect(self.browse_files)
        browse_btn.setFixedWidth(100)
        
        file_select_layout.addWidget(self.file_path_edit)
        file_select_layout.addWidget(browse_btn)
        
        # 文件列表
        self.file_list = QTextEdit()
        self.file_list.setPlaceholderText("待轉(zhuǎn)換文件列表將顯示在這里...")
        self.file_list.setMaximumHeight(80)
        self.file_list.setReadOnly(True)
        
        layout.addLayout(file_select_layout)
        layout.addWidget(self.file_list)
        
        return group
        
    def create_output_group(self):
        """創(chuàng)建輸出區(qū)域"""
        group = QGroupBox("拼音結(jié)果 ??")
        layout = QVBoxLayout(group)
        
        self.output_text = QTextEdit()
        self.output_text.setReadOnly(True)
        self.output_text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        layout.addWidget(self.output_text)
        
        # 發(fā)音按鈕
        self.speak_btn = QPushButton("朗讀拼音 ??")
        self.speak_btn.setObjectName("speakBtn")
        self.speak_btn.clicked.connect(self.speak_pinyin)
        self.speak_btn.setFixedWidth(150)
        
        speak_layout = QHBoxLayout()
        speak_layout.addStretch()
        speak_layout.addWidget(self.speak_btn)
        speak_layout.addStretch()
        
        layout.addLayout(speak_layout)
        
        return group
        
    def create_button_frame(self):
        """創(chuàng)建底部按鈕區(qū)域"""
        frame = QFrame()
        layout = QHBoxLayout(frame)
        
        self.clear_btn = QPushButton("清空 ???")
        self.clear_btn.setObjectName("clearBtn")
        self.clear_btn.clicked.connect(self.clear_text)
        
        self.copy_btn = QPushButton("復(fù)制結(jié)果 ??")
        self.copy_btn.setObjectName("copyBtn")
        self.copy_btn.clicked.connect(self.copy_result)
        
        self.exit_btn = QPushButton("退出 ??")
        self.exit_btn.setObjectName("exitBtn")
        self.exit_btn.clicked.connect(self.close)
        
        layout.addWidget(self.clear_btn)
        layout.addWidget(self.copy_btn)
        layout.addStretch()
        layout.addWidget(self.exit_btn)
        
        return frame
        
    def browse_files(self):
        """選擇多個(gè)文件"""
        files, _ = QFileDialog.getOpenFileNames(
            self, "選擇要轉(zhuǎn)換的文件", "", 
            "文本文件 (*.txt);;所有文件 (*)"
        )
        
        if files:
            self.file_path_edit.setText(f"{len(files)} 個(gè)文件已選擇")
            self.file_list.clear()
            self.file_list.append("\n".join(files))
        
    def start_file_conversion(self):
        """開(kāi)始批量轉(zhuǎn)換文件"""
        files_text = self.file_list.toPlainText().strip()
        if not files_text:
            QMessageBox.warning(self, "警告", "請(qǐng)先選擇要轉(zhuǎn)換的文件!")
            return
            
        files = [f.strip() for f in files_text.split("\n") if f.strip()]
        valid_files = []
        
        for f in files:
            if os.path.isfile(f):
                valid_files.append(f)
            else:
                QMessageBox.warning(self, "警告", f"文件不存在: {f}")
                
        if not valid_files:
            return
            
        selected_id = self.style_group.checkedId()
        style_name, _ = self.style_mapping.get(selected_id, ("normal", Style.NORMAL))
        
        # 創(chuàng)建并啟動(dòng)轉(zhuǎn)換線程
        self.converter_thread = FileConverterThread(
            valid_files,
            style_name,
            self.punctuation_cb.isChecked()
        )
        
        self.converter_thread.progress_signal.connect(self.update_progress)
        self.converter_thread.finished_signal.connect(self.conversion_finished)
        self.converter_thread.error_signal.connect(self.show_conversion_error)
        
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.stop_btn.setEnabled(True)
        self.convert_file_btn.setEnabled(False)
        
        self.converter_thread.start()
        
    def stop_file_conversion(self):
        """停止文件轉(zhuǎn)換"""
        if hasattr(self, 'converter_thread'):
            self.converter_thread.stop()
            self.converter_thread.wait()
            self.progress_bar.setVisible(False)
            self.stop_btn.setEnabled(False)
            self.convert_file_btn.setEnabled(True)
            QMessageBox.information(self, "信息", "文件轉(zhuǎn)換已停止")
        
    def update_progress(self, value):
        """更新進(jìn)度條"""
        self.progress_bar.setValue(value)
        
    def conversion_finished(self, results):
        """文件轉(zhuǎn)換完成"""
        self.progress_bar.setVisible(False)
        self.stop_btn.setEnabled(False)
        self.convert_file_btn.setEnabled(True)
        
        success_count = len(results)
        if success_count > 0:
            msg = f"成功轉(zhuǎn)換 {success_count} 個(gè)文件:\n\n"
            msg += "\n".join([f"原文件: {inp}\n保存到: {out}\n" for inp, out in results])
            QMessageBox.information(self, "轉(zhuǎn)換完成", msg)
        else:
            QMessageBox.information(self, "轉(zhuǎn)換完成", "沒(méi)有文件被轉(zhuǎn)換")
        
    def show_conversion_error(self, error_msg):
        """顯示轉(zhuǎn)換錯(cuò)誤"""
        QMessageBox.warning(self, "轉(zhuǎn)換錯(cuò)誤", error_msg)
        
    def speak_pinyin(self):
        """朗讀拼音結(jié)果"""
        pinyin_text = self.output_text.toPlainText().strip()
        if not pinyin_text:
            QMessageBox.warning(self, "警告", "沒(méi)有可朗讀的內(nèi)容!")
            return
            
        try:
            # 更新按鈕狀態(tài)
            self.speak_btn.setEnabled(False)
            self.speak_btn.setText("朗讀中...")
            QApplication.processEvents()  # 強(qiáng)制更新UI
            
            # 獲取發(fā)音設(shè)置
            lang = self.lang_combo.currentData()
            
            # 開(kāi)始朗讀
            self.tts_engine.speak(pinyin_text, lang=lang)
            
        except Exception as e:
            QMessageBox.critical(self, "錯(cuò)誤", f"朗讀時(shí)出錯(cuò):\n{str(e)}")
        finally:
            self.speak_btn.setEnabled(True)
            self.speak_btn.setText("朗讀拼音 ??")
            
    def convert_text(self):
        """轉(zhuǎn)換文本為拼音"""
        input_text = self.input_text.toPlainText().strip()
        if not input_text:
            QMessageBox.warning(self, "警告 ??", "請(qǐng)輸入要轉(zhuǎn)換的漢字內(nèi)容!")
            return

        try:
            selected_id = self.style_group.checkedId()
            style_name, style_enum = self.style_mapping.get(selected_id, ("normal", Style.NORMAL))

            request = TextRequest(
                text=input_text,
                style=style_name,
                keep_punctuation=self.punctuation_cb.isChecked()
            )

            converter = PinyinConverter(request.text)

            if request.keep_punctuation:
                converter.replace()
                result = converter.out_pinyin(style=style_enum)
            else:
                converter.del_biandian()
                result = converter.out_lazy_pinyin(style=style_enum)

            self.output_text.setPlainText(result)

        except Exception as e:
            QMessageBox.critical(self, "錯(cuò)誤 ?", f"轉(zhuǎn)換過(guò)程中出現(xiàn)錯(cuò)誤:\n{str(e)}")

    def clear_text(self):
        self.input_text.clear()
        self.output_text.clear()

    def copy_result(self):
        result = self.output_text.toPlainText().strip()
        if result:
            clipboard = QApplication.clipboard()
            clipboard.setText(result)
            QMessageBox.information(self, "成功 ?", "結(jié)果已復(fù)制到剪貼板!")
        else:
            QMessageBox.warning(self, "警告 ??", "沒(méi)有可復(fù)制的結(jié)果!")
            
    def closeEvent(self, event):
        """關(guān)閉窗口時(shí)停止所有線程"""
        if hasattr(self, 'converter_thread') and self.converter_thread.isRunning():
            self.converter_thread.stop()
            self.converter_thread.wait()
        self.tts_engine.cleanup()
        event.accept()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    
    # 設(shè)置應(yīng)用程序字體
    font = QFont()
    font.setFamily("Microsoft YaHei" if sys.platform == "win32" else "PingFang SC")
    font.setPointSize(10)
    app.setFont(font)
    
    window = PinyinConverterApp()
    window.show()
    sys.exit(app.exec_())

項(xiàng)目結(jié)構(gòu):

pinyin-converter/
├── main.py            # 主程序入口
├── converter.py       # 核心轉(zhuǎn)換邏輯
├── tts_engine.py      # 語(yǔ)音合成模塊
├── requirements.txt   # 依賴文件
└── README.md          # 使用說(shuō)明

技術(shù)深度解析

1. 拼音轉(zhuǎn)換算法優(yōu)化

傳統(tǒng)拼音轉(zhuǎn)換采用逐字查詢方式,效率較低。本工具使用pypinyin庫(kù)的批量處理接口,并針對(duì)長(zhǎng)文本進(jìn)行了優(yōu)化:

# 高效處理長(zhǎng)文本
def batch_convert(text):
    # 分段處理避免內(nèi)存溢出
    chunk_size = 500
    return ''.join([pinyin(chunk) for chunk in 
                  [text[i:i+chunk_size] 
                  for i in range(0, len(text), chunk_size)])

2. 多線程與資源管理

采用QThread實(shí)現(xiàn)后臺(tái)處理,同時(shí)注意資源清理:

def closeEvent(self, event):
    if self.converter_thread.isRunning():
        self.converter_thread.terminate()
    self.tts_engine.cleanup()

3. 國(guó)際化支持

通過(guò)Pydantic模型驗(yàn)證輸入?yún)?shù):

class TextRequest(BaseModel):
    text: Union[str, List[str]]
    style: str = "normal"
    keep_punctuation: bool = False

使用教程

基本轉(zhuǎn)換

  • 在輸入框粘貼中文文本
  • 選擇拼音風(fēng)格
  • 點(diǎn)擊"轉(zhuǎn)換"按鈕

批量處理

  • 點(diǎn)擊"選擇文件"添加多個(gè)文本文件
  • 設(shè)置轉(zhuǎn)換選項(xiàng)
  • 點(diǎn)擊"批量轉(zhuǎn)換"

文本朗讀

  • 轉(zhuǎn)換完成后點(diǎn)擊"朗讀"按鈕
  • 可調(diào)整語(yǔ)速和語(yǔ)言

性能優(yōu)化建議

緩存機(jī)制

@lru_cache(maxsize=1024)
def get_pinyin(char):
    return pinyin(char)[0][0]

預(yù)處理常用字庫(kù)

  • 加載常用字拼音映射表
  • 減少庫(kù)函數(shù)調(diào)用開(kāi)銷(xiāo)

異步加載

async def async_convert(text):
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(None, convert, text)

總結(jié)與展望

本工具通過(guò)PyQt5實(shí)現(xiàn)了專(zhuān)業(yè)的漢字轉(zhuǎn)拼音功能,具有以下優(yōu)勢(shì):

  • 支持多種拼音風(fēng)格輸出
  • 集成文本朗讀功能
  • 批量文件處理能力
  • 友好的用戶界面

未來(lái)可擴(kuò)展方向:

  • 添加拼音標(biāo)注HTML導(dǎo)出
  • 支持更多方言拼音
  • 實(shí)現(xiàn)OCR圖片轉(zhuǎn)拼音
  • 開(kāi)發(fā)在線API服務(wù)

附錄:常見(jiàn)問(wèn)題解答

Q: 轉(zhuǎn)換結(jié)果出現(xiàn)生僻字錯(cuò)誤怎么辦?

A: 更新pypinyin庫(kù)到最新版本,或手動(dòng)添加自定義詞典。

Q: 如何提高批量轉(zhuǎn)換速度?

A: 1. 關(guān)閉實(shí)時(shí)預(yù)覽 2. 增加線程池大小 3. 使用SSD存儲(chǔ)

Q: 朗讀功能不工作?

A: 檢查:1. 網(wǎng)絡(luò)連接 2. 音頻驅(qū)動(dòng) 3. 臨時(shí)文件權(quán)限

到此這篇關(guān)于基于Python+PyQt5實(shí)現(xiàn)漢字轉(zhuǎn)拼音的智能轉(zhuǎn)換工具的文章就介紹到這了,更多相關(guān)Python漢字轉(zhuǎn)拼音內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python計(jì)算三維矢量幅度的方法

    Python計(jì)算三維矢量幅度的方法

    這篇文章主要介紹了Python計(jì)算三維矢量幅度的方法,涉及Python矢量運(yùn)算的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • Python自動(dòng)化辦公的十大場(chǎng)景腳本分享

    Python自動(dòng)化辦公的十大場(chǎng)景腳本分享

    作為一名程序員,我深知重復(fù)性工作是時(shí)間殺手,每天花?1?小時(shí)整理報(bào)表,下載數(shù)據(jù),處理文件,一周就是?5?小時(shí),一個(gè)月就是?20?小時(shí),本文整理了?Python?自動(dòng)化了工作中的?10?個(gè)重復(fù)場(chǎng)景,代碼已開(kāi)源,有需要的可以了解下
    2026-03-03
  • python實(shí)現(xiàn)三壺謎題的示例詳解

    python實(shí)現(xiàn)三壺謎題的示例詳解

    這篇文章主要介紹了python實(shí)現(xiàn)三壺謎題功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 淺談Python數(shù)據(jù)處理csv的應(yīng)用小結(jié)

    淺談Python數(shù)據(jù)處理csv的應(yīng)用小結(jié)

    這篇文章主要介紹了Python數(shù)據(jù)處理csv的簡(jiǎn)單應(yīng)用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • Python利用OpenCV和skimage實(shí)現(xiàn)圖像邊緣檢測(cè)

    Python利用OpenCV和skimage實(shí)現(xiàn)圖像邊緣檢測(cè)

    提取圖片的邊緣信息是底層數(shù)字圖像處理的基本任務(wù)之一。本文將通過(guò)OpenCV和skimage的?Canny?算法實(shí)現(xiàn)圖像邊緣檢測(cè),感興趣的可以了解一下
    2022-12-12
  • Python文件的操作處理詳解

    Python文件的操作處理詳解

    今天這篇文章給大家介紹Python文件的操作處理,文章內(nèi)容介紹的很詳細(xì),有需要的可以參考借鑒,希望能夠給你帶來(lái)幫助
    2021-10-10
  • ndarray的轉(zhuǎn)置(numpy.transpose()與A.T命令對(duì)比分析)

    ndarray的轉(zhuǎn)置(numpy.transpose()與A.T命令對(duì)比分析)

    這篇文章主要介紹了ndarray的轉(zhuǎn)置(numpy.transpose()與A.T命令對(duì)比分析),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 基于python元祖與字典與集合的粗淺認(rèn)識(shí)

    基于python元祖與字典與集合的粗淺認(rèn)識(shí)

    下面小編就為大家?guī)?lái)一篇基于python元祖與字典與集合的粗淺認(rèn)識(shí)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 解決pytorch中的kl divergence計(jì)算問(wèn)題

    解決pytorch中的kl divergence計(jì)算問(wèn)題

    這篇文章主要介紹了解決pytorch中的kl divergence計(jì)算問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • python日志logging模塊使用方法分析

    python日志logging模塊使用方法分析

    這篇文章主要介紹了python日志logging模塊使用方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Python日志logging模塊相關(guān)API函數(shù)與應(yīng)用技巧,需要的朋友可以參考下
    2019-05-05

最新評(píng)論

高碑店市| 同仁县| 扎鲁特旗| 通江县| 屯留县| 长海县| 松江区| 无锡市| 阿荣旗| 福海县| 白水县| 静安区| 玉环县| 鄂尔多斯市| 繁昌县| 惠安县| 华亭县| 青河县| 西充县| 莱西市| 文成县| 东乡| 嘉义市| 若羌县| 利川市| 凉城县| 忻城县| 曲周县| 陇西县| 红安县| 开化县| 藁城市| 樟树市| 红桥区| 德安县| 河西区| 屯昌县| 扶余县| 民和| 新化县| 宁晋县|