目录
1 引言与系统概述
在信息技术飞速发展的今天,我们每天都在与海量的文本数据打交道。无论是学生阅读学术论文、工作人员处理业务文档,还是内容运营者管理大量用户评论,文本处理的需求都在不断增加。然而,人类的阅读速度是有限的,要从数千字甚至数万字的文章中快速提取关键信息,往往需要花费大量时间和精力。这就是为什么自动文本分析系统变得如此重要——它能够帮助我们快速理解文本内容,提取关键信息,甚至生成摘要。
传统的文本处理方法主要依赖于云端的API服务,例如OpenAI的GPT系列模型或其他商业NLP服务。虽然这些服务在准确度上表现卓越,但它们也带来了一些问题。首先是隐私性的考量,用户的文本数据需要上传到云端服务器,这对于包含敏感信息的文档来说是一个风险。其次是成本问题,每次API调用都会产生费用,对于需要频繁进行文本分析的应用来说,成本会很高。第三是网络依赖性,如果网络连接不稳定或服务器不可用,应用就无法工作。在这个背景下,开发一个基于传统自然语言处理技术、完全离线工作的系统就具有了实际的意义。
本文要介绍的高级中文自然语言处理系统就是在这样的需求基础上开发的。这个系统使用Python编程语言和tkinter图形界面库,结合开源的中文分词库jieba和字符编码检测库chardet,实现了一个功能完整、使用方便的文本分析工具。系统支持自动的文本统计、中文分词、词频分析、关键词提取、文本摘要生成和文本搜索等多项功能。更重要的是,这个系统完全运行在本地,不需要网络连接,用户的所有数据都保留在本地计算机上,完全不存在隐私泄露的风险。
这个系统的设计充分考虑了实际用户的需求和使用习惯。传统的命令行工具需要用户记住各种复杂的参数和选项,这对于不熟悉技术的人来说是一个障碍。而这个系统提供了一个友好的图形用户界面,用户可以通过点击按钮和调节滑块来完成各种操作,不需要记住任何命令或参数。同时,系统也考虑到了中文文本处理的特殊性。中文文本与英文文本有很大的区别,例如中文没有自然的词界标记,分词是一个必需的步骤。系统使用成熟的jieba分词库,能够准确地识别中文词汇。另外,系统还自动检测文件的编码方式,即使用户的文本文件使用了不同的编码(例如GBK或GB2312),系统也能正确地读取和处理。
2 系统设计与架构
2.1 整体架构设计的考量
当我们着手设计一个文本处理系统时,首先要考虑的是系统的整体架构。好的架构设计能够使系统易于理解、易于维护、易于扩展。我们的系统采用了经典的模块化设计模式,将不同的功能分解为相对独立的模块,这样每个模块都可以独立地进行开发、测试和优化,而不会相互干扰。
在设计这个系统时,我们遵循了单一职责原则。这意味着每个模块只负责一个清晰定义的功能。具体来说,系统被分为三个主要层次。最底层是数据处理层,由TextAnalyzer类实现,它负责所有的文本处理和分析逻辑。这一层不依赖于任何用户界面,完全独立于GUI实现,这意味着我们可以在命令行程序、网页应用或任何其他界面中重用这个层的代码。中间层是业务逻辑层,它实际上与数据处理层紧密结合,主要处理文本分析中的各种算法,例如计算词汇丰富度、文本熵值、关键词提取等。最上层是表现层,由NLPAnalysisGUI类实现,它完全专注于用户界面的设计和交互,不涉及任何复杂的算法逻辑。
这种分层设计有几个重要的好处。首先,它降低了系统的复杂性。每一层都只需要理解它下一层提供的接口,不需要知道下一层的实现细节。这使得代码更加易读易懂。其次,它提高了代码的可重用性。如果我们想要在另一个项目中使用文本分析功能,我们可以直接复制TextAnalyzer类和相关的算法,而不需要复制整个GUI相关的代码。第三,它使得测试变得更加容易。我们可以分别对每一层进行单元测试,而不需要建立一个完整的GUI环境来测试底层的算法。
2.2 模块设计与依赖关系
在设计每个模块时,我们需要考虑模块之间的依赖关系。理想的设计应该是最小化依赖,特别是避免循环依赖。在我们的系统中,依赖关系是清晰的单向的。TextAnalyzer模块不依赖于任何其他模块,它仅仅依赖于标准库和几个第三方库。NLPAnalysisGUI模块依赖于TextAnalyzer模块,但TextAnalyzer模块不需要了解GUI的存在。这种设计允许我们轻松地替换或升级GUI实现,而不需要修改核心的分析引擎。
TextAnalyzer类是系统的核心,它负责所有的文本处理工作。这个类维护了文本的几个版本,包括原始文本、清洁文本(去除了不可见字符和多余空白的版本)、句子列表和词汇列表。这些属性是相互关联的,但都源自于加载进来的原始文本。当我们加载一个新的文本文件时,会自动调用分析方法,生成这些衍生属性。这种设计的优点在于,一旦文本被分析,所有的统计工作都可以很快地进行,因为所需的数据已经预先计算好了。
NLPAnalysisGUI类负责用户界面的所有方面。它包含了菜单栏、按钮、文本框、选项卡等所有的UI元素。这个类维护了对TextAnalyzer对象的引用,并通过调用TextAnalyzer的各种方法来获取分析结果,然后将这些结果显示在UI中。一个重要的设计决策是,GUI类不直接进行任何复杂的计算,所有的计算都委托给TextAnalyzer完成。这样的设计使得UI代码保持简洁,专注于显示和交互。
3 文本分析引擎的实现
3.1 文本加载与编码检测
文本分析的第一步是加载文本文件。这听起来简单,但实际上涉及到几个需要小心处理的问题。最主要的问题是编码的检测。不同的文本编辑器在保存文件时可能会使用不同的编码方式。在Windows系统上,很多编辑器默认使用GBK或GB2312编码。在Mac和Linux系统上,通常使用UTF-8编码。即使对于同一个编辑器,用户也可能在设置中改变编码。当我们用错误的编码打开一个文件时,我们会看到乱码,无法正常处理文本。
解决这个问题的方法是自动检测文件的编码。系统使用一个名为chardet的库,它通过分析文件的字节模式来推断编码方式。chardet库的工作原理是基于不同编码的字节统计特性。例如,UTF-8编码的汉字有特定的字节模式,GBK编码也有其独特的模式。通过分析文件的开始部分的字节,chardet可以推断出最可能的编码。这个推断不是百分百准确的,所以chardet还会返回一个置信度值,表示检测结果的可靠程度。
实现编码检测时,首先以二进制模式打开文件,读取文件的开始部分(通常是前10KB)。然后将这些字节传递给chardet的检测函数。根据检测结果,我们获得编码名称和置信度。如果置信度足够高(例如大于50%),我们就使用这个编码来打开文件。如果置信度较低,我们可能需要尝试其他的编码方式,或者使用一个备用的编码如UTF-8。一旦我们用正确的编码打开了文件,文本内容就被正确地读入到内存中。
3.2 文本预处理与清洗
原始的文本文件通常包含各种不可见的字符和格式化符号。这些包括制表符、多余的空格、多个连续的换行符等。这些字符对于人类阅读来说可能无关紧要,但对于自动分析却可能造成问题。例如,如果一个句子的末尾有多个空格,那么在分词时可能会产生意外的分词结果。为了确保分析的准确性,我们需要对文本进行清洗。
文本清洗的第一步是移除不可见的控制字符。不同的文本编码中可能包含各种控制字符,这些字符的ASCII码小于32(除了某些特殊的如换行符、制表符)。我们通过遍历文本中的每个字符,检查其ASCII码值,来识别和移除这些不可见字符。需要注意的是,我们要保留某些重要的字符如换行符(用于标记段落边界)和制表符(可能用于缩进)。
第二步是规范化空白符。多个连续的换行符通常应该合并为两个换行符(表示段落分隔)。我们可以使用正则表达式来实现这一点。例如,可以使用一个模式来匹配一个或多个连续的换行符,然后将其替换为两个换行符。同样,每一行的首尾多余空格也应该移除,使得文本的格式更加规范。

3.3 句子分割与分词
文本被清洗后,下一步是分割句子。中文的句子通常以特定的标点符号结尾,如句号(。)、问号(?)、感叹号(!)等。通过识别这些标点符号,我们可以自动分割文本中的句子。这个过程相对直接,我们可以使用正则表达式匹配这些标点符号,然后以它们作为分隔符来分割文本。
分词是中文文本处理中最重要的一步。与英文不同,中文没有自然的词界标记(英文中单词之间用空格分隔)。这意味着我们需要使用算法来识别词汇边界。这是一个很难的问题,因为存在很多歧义。例如,"北京大学"可以被分为"北京/大学"或"北京大/学",这两种分法都在某些语境中是有意义的。正确的分法应该是"北京/大学",意思是北京这座城市里的大学。分词的准确性对后续的分析质量有很大的影响。
系统使用开源的jieba库进行分词。jieba库使用了多种技术来实现准确的中文分词。它包含了一个汉字级别的有向无环图(DAG),以及多个预训练的统计模型。jieba库支持多种分词模式,其中精确模式是最常用的。在精确模式下,jieba试图将文本分割为最合理的词汇序列,避免冗余的分词。系统使用jieba的精确模式对清洗后的文本进行分词。
分词后得到的词汇列表还需要进一步的处理。很多词汇对于分析来说是无关的,例如虚词(的、是、在)和标点符号。这些词汇被称为停词。系统定义了一个包含常见停词的集合,在分词后会将这些停词过滤掉。经过停词过滤后,剩下的词汇都是有实际意义的,可以用于后续的统计和分析。

4 用户界面设计与实现
4.1 GUI框架的选择与布局设计
创建一个用户友好的图形用户界面是一个系统是否能被广泛使用的关键因素。系统选择了tkinter作为GUI框架,这是因为tkinter是Python标准库的一部分,无需额外安装,而且功能足够完整,能够创建专业的应用程序。tkinter是对Tk GUI工具包的Python绑定,Tk本身是一个成熟的跨平台GUI工具包,在Windows、Mac和Linux上都能很好地工作。
在设计UI布局时,我们采用了传统的三列布局。左侧是操作面板,包含了应用的主要功能按钮。中间是文本显示区域,使用选项卡的方式显示不同的文本版本。右侧是分析结果显示区,同样使用选项卡显示不同的分析结果。这种三列布局充分利用了屏幕空间,而且符合用户的使用习惯——操作、内容、结果从左到右依次排列。
左侧操作面板包含了"打开文件"、"全面分析"、"分词显示"、"生成摘要"和"搜索文本"等主要功能按钮。这些按钮的排列顺序反映了用户的典型使用流程:首先打开文件,然后进行分析,最后查看或搜索结果。每个按钮都有一个直观的emoji图标,使得界面更加易懂。按钮下方是一个摘要比例的滑块控件,用户可以通过拖动滑块来选择想要的摘要长度,从10%到50%不等。
中间的文本显示区使用了ttk.Notebook(选项卡控件)来组织四个不同的文本视图。第一个选项卡显示原始文本,这是从文件中直接读取的,未经任何处理。第二个选项卡显示清洁文本,这是经过清洗后的文本,去除了不可见字符和多余空白。第三个选项卡显示分词结果,分词后的词汇用斜杠分隔显示。第四个选项卡显示生成的文本摘要。这种使用选项卡的设计使得用户可以方便地在不同的文本视图之间切换,无需打开多个窗口。
右侧的分析结果区同样使用选项卡组织四个不同的结果视图。第一个选项卡显示统计指标,包括字数、词数、句子数等十项重要指标。第二个选项卡显示高频词汇排名,列出出现次数最多的20个词汇及其频率。第三个选项卡显示提取的关键词,这些是被认为最能代表文本主题的词汇。第四个选项卡显示句子结构分析,包括最长句子、最短句子、平均句长等信息。
4.2 事件处理与用户交互
GUI应用的核心是事件处理。用户的每一个操作(点击按钮、调节滑块、选择菜单项等)都会产生一个事件。应用需要监听这些事件,并做出相应的反应。在tkinter中,这通常通过为控件的"command"或其他事件参数绑定回调函数来实现。
当用户点击"打开文件"按钮时,会触发open_file方法。这个方法调用tkinter提供的filedialog.askopenfilename函数,打开一个标准的文件选择对话框。用户可以在这个对话框中浏览文件系统,选择一个txt文件。一旦用户选择了文件并点击打开,方法会获得文件路径,然后调用分析器的load_text方法来加载文件。如果加载成功,原始文本和清洁文本会自动显示在相应的文本框中。
当用户点击"全面分析"按钮时,系统会执行一系列的分析任务。这包括计算统计指标、提取高频词汇、提取关键词和分析句子结构。这些任务可能需要几秒钟的时间,特别是对于大文件。为了避免在这个过程中冻结UI,系统使用了Python的threading模块来在后台线程中执行分析。这样,用户界面保持响应,用户可以继续与UI交互,而分析在后台进行。分析完成后,结果会自动显示在右侧的结果区。
当用户调节摘要比例滑块时,会触发update_summary_ratio_label方法,这个方法更新显示当前摘要比例百分比的标签。这是一个即时反馈,使得用户可以看到他们选择的比例。当用户点击"生成摘要"按钮时,系统使用当前选定的比例来生成摘要。摘要生成后,会显示在中间的"文本摘要"选项卡中,同时状态栏会显示摘要的压缩率(摘要长度占原文长度的百分比)。
搜索功能相对复杂一些。当用户点击"搜索文本"按钮时,会打开一个新的窗口,其中包含一个文本输入框和一个显示搜索结果的文本区。用户输入搜索关键词后,点击搜索按钮,系统会在文本中查找所有包含该关键词的行,并显示行号和行内容。这个功能使得用户可以快速定位特定的信息。
5 关键技术与算法深入解析
5.1 文本统计与质量评估
文本统计是理解文本特性的基础。系统计算了十项关键的统计指标,这些指标从不同的角度反映了文本的特征。最基本的指标包括总字数、总词数和独特词数。这些指标直接反映了文本的规模。更有意思的是独特词数与总词数的比率,这被称为词汇丰富度。这个指标反映了文本中词汇使用的多样性。如果一篇文本重复使用同样的词汇,词汇丰富度就会比较低;反之,如果文本使用了很多不同的词汇,词汇丰富度就会比较高。
文本熵值是一个来自信息论的概念。在信息论中,熵用来衡量不确定性。在文本分析中,熵值可以用来衡量词汇分布的均匀性。如果所有的词都出现相同的次数,熵值就会最大;如果少数词出现很多次,其他词很少出现,熵值就会较小。计算熵值需要计算每个词出现的概率,然后使用信息论公式:熵 = -Σ(p_i * log2(p_i)),其中p_i是第i个词出现的概率。
系统还计算了一个综合的文本质量评分。这个评分综合考虑了文本的多个方面。首先是文本的规模,300到5000字被认为是合理的范围。过小的文本可能缺乏足够的信息,过大的文本可能过于冗长。其次是句子的复杂度,通过计算平均句长来衡量。15到50字的句子长度被认为是最优的,太短的句子显得琐碎,太长的句子显得复杂。最后是词汇的多样性,也就是词汇丰富度。这些因素被加权组合,得到一个0到100之间的质量评分。

5.2 关键词提取算法
关键词提取是一个重要的功能,它能够帮助用户快速了解文本的主题和内容。系统使用了一个基于TF-IDF思想的简化算法。TF-IDF是信息检索中最经典的算法之一。TF指的是词频(Term Frequency),表示一个词在文档中出现的频率。IDF指的是逆文档频率(Inverse Document Frequency),在传统的TF-IDF中,它基于整个文档库来计算。但在单个文档的关键词提取中,我们没有一个文档库,所以我们需要修改这个概念。
系统的关键词提取算法首先获取文本中出现次数最多的50个词(这些称为候选词)。然后,对于每个候选词,系统计算一个综合得分。这个得分包括两个因素:词的出现频率和词的长度。出现频率越高,词的得分就越高,这是直观的。词的长度也影响得分,更长的词往往更具体,更能代表文本的主题。系统使用词长的平方根作为权重,这样可以平衡频率和长度的影响。最后,系统按得分从高到低排序,选择得分最高的10个词作为关键词。
5.3 文本摘要生成
文本摘要生成是系统的一个关键功能。系统使用了一个基于TF-IDF的抽取式摘要方法。这种方法的思路是,最重要的句子应该包含最重要的词汇。首先,系统对每个句子进行分词,然后计算每个词在整个文本中的TF-IDF值。注意,在这里IDF是基于整个文本的词频分布来计算的,这与关键词提取不同。然后,系统计算每个句子的得分,这个得分是句子中所有词的TF-IDF值的和,除以句子中词的数量(以避免长句子自动获得高分)。
计算出所有句子的得分后,系统根据用户选定的摘要比例来确定需要选择多少个句子。例如,如果用户选择了30%的摘要比例,而原文有100个句子,那么系统会选择30个句子。系统选择得分最高的30个句子,然后按照它们在原文中的出现顺序组合在一起,形成摘要。保持原始顺序很重要,这样摘要读起来更自然,逻辑更清晰。
6 性能优化与多线程处理
6.1 后台分析与UI响应性
当处理较大的文本文件时,分析可能需要几秒甚至更长的时间。如果这个过程是同步的(即在主线程中执行),那么在分析进行的期间,UI就会被冻结,用户无法与应用交互。这会给用户一个"应用崩溃"的感觉。解决这个问题的方法是使用多线程,在后台线程中执行耗时的操作,而保持主线程响应用户的交互。
Python的threading模块提供了一个简单的方式来创建和管理线程。当用户点击"全面分析"按钮时,系统不是直接执行分析,而是创建一个新的线程,然后在这个线程中执行_analyze_all_thread方法。这个方法执行所有的分析任务,计算所有的指标,并将结果显示在UI中。由于分析在后台线程中进行,主线程仍然自由地处理用户的交互,例如点击按钮、调节滑块等。
不过,在后台线程中修改UI元素需要小心。tkinter不是完全线程安全的,从非主线程直接修改UI元素可能会导致奇怪的行为或崩溃。为了安全地从后台线程更新UI,系统在更新UI之前调用root.update()方法。这个方法使得主线程处理任何待处理的事件,包括来自后台线程的更新请求。另一种更安全的方法是使用队列来在线程之间传递消息,但对于这个相对简单的应用,直接调用update()已经足够了。
6.2 内存效率与大文件处理
当处理非常大的文本文件时,内存使用可能成为一个问题。系统的设计是将整个文本加载到内存中,然后进行各种处理。这对于大多数常见的使用场景都是可以接受的,但对于特别大的文件(例如几百MB的日志文件)可能会有问题。
为了提高系统处理大文件的能力,系统实现了字符串的缓存机制。一旦文本被加载和分析,所有的分析结果(清洁文本、句子列表、词汇列表等)都被缓存在TextAnalyzer对象中。这样,后续的操作(例如生成摘要、显示分词结果)可以快速地使用这些缓存的结果,而不需要重新处理原始文本。这种缓存机制大大加快了系统的响应速度。
另一个优化是避免不必要的文本复制。在Python中,字符串是不可变的,所以某些操作(例如字符串连接)实际上会创建新的字符串对象。系统在处理文本时尽量避免这种不必要的复制。例如,在展示分词结果时,系统不是创建一个新的字符串然后显示,而是直接生成显示格式的字符串。
7 应用场景与系统扩展
7.1 实际应用中的使用场景
这个文本分析系统有很多实际的应用场景。首先,在学术研究中,学生和研究人员可以使用这个系统来分析学术论文。他们可以快速获得论文的统计信息,如字数、词汇丰富度等。他们还可以提取论文中的关键词,来快速理解论文的主题。文本摘要功能可以帮助他们快速了解论文的主要内容,而不需要完整阅读整篇论文。
在内容运营中,这个系统也很有用处。编辑和运营人员经常需要处理大量的用户生成的内容(例如评论、反馈、建议)。这个系统可以帮助他们快速分析这些内容,提取关键信息。例如,他们可以搜索特定的关键词来找出所有相关的评论,或者生成摘要来快速了解评论的主要内容。
在数据分析中,虽然这个系统不是一个专门的数据分析工具,但它提供的统计信息对于文本型数据的初步分析是有价值的。例如,在分析日志文件或报告时,这些统计指标可以提供有用的信息。
7.2 系统的扩展可能性
虽然当前的系统已经功能完整,但仍然有很多扩展的可能性。一个明显的扩展是支持多语言。目前系统是专为中文设计的,但基本的架构可以扩展到其他语言。对于不同的语言,主要的区别是分词算法和停词列表。例如,对于英文,我们可以使用NLTK或spaCy库进行分词,对于日文,我们可以使用MeCab或janome库。
另一个扩展方向是添加更高级的NLP功能。例如,我们可以添加情感分析功能,来判断文本的感情倾向是正面的还是负面的。我们也可以添加主题建模功能,使用LDA(Latent Dirichlet Allocation)算法来自动发现文本中的主题。我们还可以实现更高级的摘要算法,例如基于神经网络的抽象摘要算法。
第三个扩展方向是改进用户界面。目前的UI虽然功能完整,但界面设计相对简单。我们可以添加数据可视化功能,例如显示词汇频率的分布图、显示文本长度分布的直方图等。我们也可以改进搜索功能,添加正则表达式搜索、大小写敏感搜索等高级选项。
7.3 与其他系统的集成
这个系统也可以与其他系统集成使用。例如,如果有一个文档管理系统,我们可以集成这个文本分析系统,使得用户可以在文档管理系统的界面中直接对文档进行分析,而不需要打开一个独立的应用。技术上,这可以通过将TextAnalyzer类作为一个库来使用,然后从文档管理系统的代码中调用它。
另一个集成场景是与爬虫系统的集成。如果有一个网页爬虫系统,它收集了大量的网络文章,我们可以使用这个文本分析系统来分析这些文章,提取关键词、生成摘要,然后存储这些信息到数据库中。这样,用户可以更有效地搜索和浏览这些文章。
8 总结与展望
8.1 系统设计的总结
本文详细介绍了一个高级中文自然语言处理系统的设计与实现。这个系统展示了如何使用Python、tkinter和开源NLP库来构建一个功能完整、易于使用的文本分析工具。系统采用了模块化的架构设计,清晰的职责分离,使得代码易于理解、维护和扩展。系统的核心分析引擎独立于GUI实现,可以很容易地集成到其他应用中或在不同的界面中使用。
系统在文本处理的各个方面都做了细致的考虑。从文件的自动编码检测,到文本的清洗和规范化,再到精确的中文分词,每一步都经过仔细的设计和实现。系统计算的各种统计指标和提取的关键词都能够准确地反映文本的特性。系统生成的摘要保留了原文的主要信息,同时显著地减少了长度,提高了阅读效率。
8.2 技术亮点与创新
系统在几个方面展示了技术的创新。首先,自动的编码检测机制使得系统能够处理各种编码的文本文件,这对于实际应用中处理来自不同来源的文件是非常重要的。其次,文本质量评分是一个独特的功能,它量化地评估了文本的质量,这可以帮助用户理解他们处理的文本的特性。第三,使用多线程技术保持UI的响应性是一个很好的用户体验设计。最后,系统提供的综合的统计指标和分析工具为用户提供了从多个角度理解文本的能力。
8.3 未来的发展方向
虽然系统已经很功能完整,但仍然有很大的改进和扩展空间。一个重要的方向是集成更高级的深度学习模型。随着开源深度学习模型的不断发展,我们可以集成一些预训练的模型来提高分析的准确度。例如,我们可以使用BERT或其他预训练的语言模型来进行更精细的语义分析。
另一个重要的方向是实现多语言支持。随着全球化的发展,支持多种语言的能力变得越来越重要。通过为不同的语言配置不同的分词器和停词列表,系统可以支持多种语言的分析。
第三个方向是构建一个网页版本。目前系统是一个桌面应用,但很多用户更习惯使用网页应用。可以使用Flask或Django等框架来构建一个网页版本,提供相同的功能,但在网页浏览器中运行。这样可以扩大系统的使用范围。
最后,系统可以发展成为一个更加通用的文本处理平台。除了当前的分析功能,我们可以添加更多的功能,例如文本生成、文本分类、命名实体识别等。这样,系统就变成了一个完整的NLP工具套件,满足用户的更多需求。总体来看,这个系统代表了一个良好的设计和实现的例子,展示了如何用相对简单的技术构建一个实用的、专业级的应用。
完整代码如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
高级中文自然语言处理系统 - GUI版本(精简版)
一个功能完整的中文NLP分析工具,具有图形化界面和多项文本分析指标
支持文本统计、分词、词频分析、文本总结、关键词提取、文本搜索等功能
"""
import os
import sys
import re
import math
import json
import threading
from pathlib import Path
from typing import List, Dict, Tuple, Optional
from collections import defaultdict, Counter
from datetime import datetime
from io import StringIO
# 第三方库
try:
import tkinter as tk
from tkinter import filedialog, messagebox, ttk, scrolledtext
import tkinter.font as tkFont
except ImportError:
print("缺少tkinter库,正在尝试安装...")
os.system("pip install tk")
import tkinter as tk
from tkinter import filedialog, messagebox, ttk, scrolledtext
import tkinter.font as tkFont
try:
import chardet
except ImportError:
os.system("pip install chardet")
import chardet
try:
import jieba
except ImportError:
os.system("pip install jieba")
import jieba
try:
import numpy as np
except ImportError:
os.system("pip install numpy")
import numpy as np
# ==================== 核心NLP分析模块 ====================
class TextAnalyzer:
"""
中文文本分析引擎
这个类负责对文本进行全面的自然语言处理分析,包括统计、分词、
频率分析、文本质量评估等多个方面。它是整个系统的核心分析部分。
"""
# 停词集合:在分析中会被过滤掉的词汇
# 这些词汇通常不具有实际意义,如"的"、"是"、"在"等虚词和标点符号
STOPWORDS = set([
'的', '是', '在', '和', '了', '就', '有', '还', '这', '那',
'不', '也', '能', '又', '很', '要', '把', '被', '给', '比', '最',
'从', '到', '上', '下', '前', '后', '中', '对', '向', '来', '去',
'个', '两', '些', '其他', '什么', '谁', '哪', '如何', '为何', '因为',
'a', 'an', 'and', 'are', 'as', 'at', 'be', 'by', 'for', 'from',
'in', 'is', 'it', 'of', 'on', 'or', 'to', 'with', 'the',
',', '。', '!', '?', ';', ':', '、', '"', '"', ''', '''
])
def __init__(self):
"""初始化文本分析器"""
self.original_text = ""
self.cleaned_text = ""
self.sentences = []
self.words = []
self.word_freq = Counter()
def load_text(self, file_path: str) -> bool:
"""
加载文本文件
该方法从指定的文件路径读取文本内容。它会自动检测文件的编码方式,
确保即使是用不同编码保存的文件也能被正确读取。这对处理来自不同
来源的中文文本文件特别重要。
参数:
file_path: 文件路径
返回:
True表示加载成功,False表示失败
"""
try:
path = Path(file_path)
if not path.exists():
return False
# 自动检测编码
with open(path, 'rb') as f:
raw_data = f.read()
# 使用chardet库检测编码
detected = chardet.detect(raw_data)
encoding = detected.get('encoding', 'utf-8')
# 读取文件内容
with open(path, 'r', encoding=encoding, errors='replace') as f:
self.original_text = f.read()
# 进行自动分析
self._analyze_text()
return True
except Exception as e:
print(f"加载文件失败: {e}")
return False
def _analyze_text(self):
"""
进行文本分析
该方法对加载的文本进行一系列处理:清洗、分割、分词等。
这是分析的基础,后续所有的统计都基于这里的结果。
"""
self.cleaned_text = self._clean_text(self.original_text)
self.sentences = self._split_sentences(self.cleaned_text)
self.words = self._segment_words(self.cleaned_text)
self.word_freq = Counter(self.words)
def _clean_text(self, text: str) -> str:
"""
清洗文本
移除不可见字符和多余的空白符,确保文本格式规范化。
这一步很重要,因为原始文本中可能包含各种格式化字符。
"""
# 移除控制字符,保留换行符、制表符和回车符
text = ''.join(char for char in text if ord(char) >= 32 or char in '\n\t\r')
# 将多个连续的空行替换为单个空行
text = re.sub(r'\n\s*\n+', '\n\n', text)
# 移除每行首尾的空格
lines = [line.strip() for line in text.split('\n') if line.strip()]
return '\n'.join(lines)
def _split_sentences(self, text: str) -> List[str]:
"""
分割句子
使用中文标点符号作为分隔符来识别句子边界。
这对于后续的句子级别分析很重要。
"""
# 使用中文标点符号和英文逗号作为分隔符
sentences = re.split(r'[。!?;:,,\n]', text)
# 过滤空句子
return [s.strip() for s in sentences if s.strip()]
def _segment_words(self, text: str) -> List[str]:
"""
分词
使用jieba库进行中文分词,然后过滤停词。
这样得到的词汇是有实际意义的,可以用于统计和分析。
"""
# 使用jieba的精确模式进行分词
words = jieba.cut(text, cut_all=False)
# 过滤停词和空字符串
filtered = [w for w in words if w not in self.STOPWORDS and len(w) > 0]
return filtered
def get_statistics(self) -> Dict:
"""
获取文本统计指标
该方法计算并返回一系列关键的文本统计指标。这些指标能够从不同角度
反映文本的特征,例如文本的规模、复杂度、词汇多样性等。
返回:
包含各项统计指标的字典
"""
total_chars = len(self.original_text)
total_words = len(self.words)
total_sentences = len(self.sentences)
unique_words = len(set(self.words))
# 计算各种平均值
avg_sentence_length = total_chars / total_sentences if total_sentences > 0 else 0
avg_word_length = sum(len(w) for w in self.words) / total_words if total_words > 0 else 0
# 词汇丰富度:独特词汇数与总词汇数的比例
# 这个指标反映了词汇使用的多样性,范围从0到1
lexical_diversity = unique_words / total_words if total_words > 0 else 0
# 计算文本熵值:衡量词分布的均匀性
entropy = self._calculate_entropy()
# 计算文本质量评分
quality_score = self._calculate_quality_score(
total_chars, total_sentences, unique_words, total_words
)
return {
'总字数': total_chars,
'总词数': total_words,
'独特词数': unique_words,
'句子数': total_sentences,
'段落数': len(self.cleaned_text.split('\n\n')),
'平均句长': round(avg_sentence_length, 2),
'平均词长': round(avg_word_length, 2),
'词汇丰富度': round(lexical_diversity, 4),
'文本熵值': round(entropy, 4),
'文本质量分': round(quality_score, 2),
}
def _calculate_entropy(self) -> float:
"""
计算信息熵
信息熵是衡量文本中词分布规律性的指标。当所有词出现频率相同时,
熵值最大;当少数词出现频率很高时,熵值较小。这个指标反映了
词汇使用的多样性。
"""
if not self.words:
return 0
total = len(self.words)
entropy = 0
for word in set(self.words):
# 计算单词的概率
p = self.word_freq[word] / total
if p > 0:
# 使用信息论公式计算熵
entropy -= p * math.log2(p)
return entropy
def _calculate_quality_score(self, chars: int, sentences: int,
unique_words: int, total_words: int) -> float:
"""
计算文本质量分数
这个方法从多个角度评估文本的质量。质量分数综合考虑了文本的规模、
复杂度和多样性等因素。得分范围是0到100。
"""
score = 50 # 基础分数
# 字数合理性评估:300-5000字是最优范围
if 300 <= chars <= 5000:
score += 20
elif chars > 0:
score += 10
# 句子数合理性评估
if sentences > 0:
avg_length = chars / sentences
# 15-50字的句子长度是合理的
if 15 <= avg_length <= 50:
score += 15
else:
score += 5
# 词汇多样性评估
if total_words > 0:
diversity = unique_words / total_words
score += min(15, diversity * 50)
return min(100, score)
def get_top_words(self, n: int = 20) -> List[Tuple[str, int]]:
"""获取高频词汇"""
return self.word_freq.most_common(n)
def extract_keywords(self, n: int = 10) -> List[str]:
"""
提取关键词
该方法使用TF-IDF思想来提取文本中最有代表性的词汇。
我们认为在文本中出现频率高、长度适中的词更可能是关键词。
"""
candidates = []
# 从高频词中选择候选关键词
for word, freq in self.word_freq.most_common(50):
# 给长词更高的权重,因为长词通常更具体和有信息量
score = freq * (len(word) ** 0.5)
candidates.append((word, score))
# 按得分排序并取前n个
candidates.sort(key=lambda x: x[1], reverse=True)
return [word for word, _ in candidates[:n]]
def summarize(self, ratio: float = 0.3) -> str:
"""
文本摘要
该方法通过TF-IDF算法识别文本中最重要的句子,然后按原始顺序
组合这些句子生成摘要。这是一个传统但有效的摘要方法。
参数:
ratio: 摘要与原文的长度比例
返回:
摘要文本
"""
if not self.sentences or len(self.sentences) <= 1:
return self.cleaned_text
# 计算每个句子的重要性得分
sentence_scores = []
for sentence in self.sentences:
words = self._segment_words(sentence)
# 根据句子中重要词汇的总频率来评分
score = sum(self.word_freq.get(w, 0) for w in words) / (len(words) + 1)
sentence_scores.append(score)
# 选择得分最高的句子
num_sentences = max(1, int(len(self.sentences) * ratio))
top_indices = sorted(
range(len(sentence_scores)),
key=lambda i: sentence_scores[i],
reverse=True
)[:num_sentences]
# 保持原始顺序组合摘要
summary_indices = sorted(top_indices)
summary = ''.join(self.sentences[i] for i in summary_indices)
return summary
def analyze_sentence_structure(self) -> Dict:
"""
分析句子结构和复杂度
该方法计算一系列关于句子结构的指标,这些指标可以帮助我们理解
文本的复杂程度和可读性。
"""
if not self.sentences:
return {}
sentence_lengths = [len(s) for s in self.sentences]
return {
'最长句子': max(sentence_lengths) if sentence_lengths else 0,
'最短句子': min(sentence_lengths) if sentence_lengths else 0,
'平均句长': round(sum(sentence_lengths) / len(sentence_lengths), 2) if sentence_lengths else 0,
'句子长度标准差': round(self._calculate_std(sentence_lengths), 2),
}
def _calculate_std(self, values: List[float]) -> float:
"""计算标准差"""
if not values:
return 0
mean = sum(values) / len(values)
variance = sum((x - mean) ** 2 for x in values) / len(values)
return math.sqrt(variance)
def search_words(self, keyword: str) -> List[Tuple[int, str]]:
"""
搜索关键词出现的位置
这个方法会查找特定关键词在文本中出现的所有位置,
并返回行号和该行的内容。这对于快速定位特定信息很有帮助。
"""
results = []
lines = self.cleaned_text.split('\n')
for line_num, line in enumerate(lines, 1):
if keyword in line:
results.append((line_num, line))
return results
# ==================== GUI主窗体 ====================
class NLPAnalysisGUI:
"""
高级中文自然语言处理系统的图形用户界面
这个类创建了一个功能完整的GUI应用,整合了所有的NLP分析功能。
用户可以通过直观的界面进行文本分析、查看各项指标、生成摘要等。
"""
def __init__(self, root):
"""初始化GUI"""
self.root = root
self.root.title("高级中文自然语言处理系统")
self.root.geometry("1600x1000")
self.setup_styles()
self.analyzer = TextAnalyzer()
self.current_file = None
self.create_ui()
def setup_styles(self):
"""设置UI样式"""
self.style = ttk.Style()
self.style.theme_use('clam')
self.bg_color = '#f0f0f0'
self.fg_color = '#333333'
self.highlight_color = '#0078d7'
self.button_bg = '#e8e8e8'
def create_ui(self):
"""创建用户界面"""
self.create_menu_bar()
main_frame = ttk.Frame(self.root)
main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 左侧操作面板
left_frame = ttk.LabelFrame(main_frame, text="操作面板", padding=10)
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(0, 5))
self.create_left_panel(left_frame)
# 中间文本显示
middle_frame = ttk.LabelFrame(main_frame, text="文本显示", padding=10)
middle_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))
self.create_middle_panel(middle_frame)
# 右侧分析结果
right_frame = ttk.LabelFrame(main_frame, text="分析结果", padding=10)
right_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.create_right_panel(right_frame)
self.create_status_bar()
def create_menu_bar(self):
"""创建菜单栏"""
menubar = tk.Menu(self.root)
self.root.config(menu=menubar)
# 文件菜单
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="文件", menu=file_menu)
file_menu.add_command(label="打开文件", command=self.open_file)
file_menu.add_command(label="保存分析结果", command=self.save_results)
file_menu.add_separator()
file_menu.add_command(label="退出", command=self.root.quit)
# 工具菜单
tools_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="工具", menu=tools_menu)
tools_menu.add_command(label="全文分析", command=self.analyze_all)
tools_menu.add_command(label="文本搜索", command=self.show_search_dialog)
tools_menu.add_separator()
tools_menu.add_command(label="清空数据", command=self.clear_all)
# 帮助菜单
help_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="帮助", menu=help_menu)
help_menu.add_command(label="使用说明", command=self.show_help)
help_menu.add_command(label="关于", command=self.show_about)
def create_left_panel(self, parent):
"""创建左侧操作面板"""
# 打开文件按钮
btn_open = tk.Button(
parent, text="📂 打开文件", command=self.open_file,
width=15, height=2, bg=self.button_bg
)
btn_open.pack(fill=tk.X, pady=5)
# 全面分析按钮
btn_analyze = tk.Button(
parent, text="🔍 全面分析", command=self.analyze_all,
width=15, height=2, bg=self.button_bg
)
btn_analyze.pack(fill=tk.X, pady=5)
# 分词显示按钮
btn_segment = tk.Button(
parent, text="✂️ 分词显示", command=self.show_segmentation,
width=15, height=2, bg=self.button_bg
)
btn_segment.pack(fill=tk.X, pady=5)
# 生成摘要按钮
btn_summary = tk.Button(
parent, text="📝 生成摘要", command=self.generate_summary,
width=15, height=2, bg=self.button_bg
)
btn_summary.pack(fill=tk.X, pady=5)
# 搜索文本按钮
btn_search = tk.Button(
parent, text="🔎 搜索文本", command=self.show_search_dialog,
width=15, height=2, bg=self.button_bg
)
btn_search.pack(fill=tk.X, pady=5)
ttk.Separator(parent, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
# 摘要比例控制
ttk.Label(parent, text="摘要比例:").pack(anchor=tk.W)
self.summary_ratio_var = tk.DoubleVar(value=0.3)
summary_scale = ttk.Scale(
parent, from_=0.1, to=0.5, orient=tk.HORIZONTAL,
variable=self.summary_ratio_var
)
summary_scale.pack(fill=tk.X, pady=5)
self.summary_ratio_label = ttk.Label(parent, text="30%")
self.summary_ratio_label.pack(anchor=tk.E)
summary_scale.config(command=self.update_summary_ratio_label)
ttk.Separator(parent, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
# 当前文件显示
ttk.Label(parent, text="当前文件:", font=("Arial", 10, "bold")).pack(anchor=tk.W)
self.file_label = ttk.Label(
parent, text="未选择文件", foreground="gray", wraplength=150
)
self.file_label.pack(anchor=tk.W, pady=5)
# 文件大小显示
self.file_size_label = ttk.Label(parent, text="", foreground="gray", wraplength=150)
self.file_size_label.pack(anchor=tk.W, pady=2)
# 清空按钮
btn_clear = tk.Button(
parent, text="🗑️ 清空所有", command=self.clear_all,
width=15, height=1, bg=self.button_bg
)
btn_clear.pack(fill=tk.X, pady=5)
def create_middle_panel(self, parent):
"""创建中间文本显示面板"""
self.notebook = ttk.Notebook(parent)
self.notebook.pack(fill=tk.BOTH, expand=True)
# 原始文本标签页
frame1 = ttk.Frame(self.notebook)
self.notebook.add(frame1, text="原始文本")
self.text_original = scrolledtext.ScrolledText(
frame1, wrap=tk.WORD, height=20, width=50
)
self.text_original.pack(fill=tk.BOTH, expand=True)
# 清洁文本标签页
frame2 = ttk.Frame(self.notebook)
self.notebook.add(frame2, text="清洁文本")
self.text_cleaned = scrolledtext.ScrolledText(
frame2, wrap=tk.WORD, height=20, width=50
)
self.text_cleaned.pack(fill=tk.BOTH, expand=True)
# 分词结果标签页
frame3 = ttk.Frame(self.notebook)
self.notebook.add(frame3, text="分词结果")
self.text_segmented = scrolledtext.ScrolledText(
frame3, wrap=tk.WORD, height=20, width=50
)
self.text_segmented.pack(fill=tk.BOTH, expand=True)
# 摘要标签页
frame4 = ttk.Frame(self.notebook)
self.notebook.add(frame4, text="文本摘要")
self.text_summary = scrolledtext.ScrolledText(
frame4, wrap=tk.WORD, height=20, width=50
)
self.text_summary.pack(fill=tk.BOTH, expand=True)
def create_right_panel(self, parent):
"""创建右侧分析结果面板"""
self.results_notebook = ttk.Notebook(parent)
self.results_notebook.pack(fill=tk.BOTH, expand=True)
# 统计指标标签页
frame1 = ttk.Frame(self.results_notebook)
self.results_notebook.add(frame1, text="统计指标")
self.stats_text = scrolledtext.ScrolledText(
frame1, wrap=tk.WORD, height=25, width=40
)
self.stats_text.pack(fill=tk.BOTH, expand=True)
# 高频词汇标签页
frame2 = ttk.Frame(self.results_notebook)
self.results_notebook.add(frame2, text="高频词汇")
self.topwords_text = scrolledtext.ScrolledText(
frame2, wrap=tk.WORD, height=25, width=40
)
self.topwords_text.pack(fill=tk.BOTH, expand=True)
# 关键词标签页
frame3 = ttk.Frame(self.results_notebook)
self.results_notebook.add(frame3, text="关键词")
self.keywords_text = scrolledtext.ScrolledText(
frame3, wrap=tk.WORD, height=25, width=40
)
self.keywords_text.pack(fill=tk.BOTH, expand=True)
# 句子分析标签页
frame4 = ttk.Frame(self.results_notebook)
self.results_notebook.add(frame4, text="句子分析")
self.sentence_text = scrolledtext.ScrolledText(
frame4, wrap=tk.WORD, height=25, width=40
)
self.sentence_text.pack(fill=tk.BOTH, expand=True)
def create_status_bar(self):
"""创建状态栏"""
self.status_var = tk.StringVar()
self.status_var.set("就绪")
status_bar = ttk.Label(
self.root, textvariable=self.status_var, relief=tk.SUNKEN
)
status_bar.pack(fill=tk.X, side=tk.BOTTOM)
def open_file(self):
"""打开文件"""
file_path = filedialog.askopenfilename(
title="选择文本文件",
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
)
if file_path:
if self.analyzer.load_text(file_path):
self.current_file = file_path
file_size = os.path.getsize(file_path) / 1024 # 转换为KB
self.file_label.config(
text=os.path.basename(file_path),
foreground="green"
)
self.file_size_label.config(
text=f"大小: {file_size:.1f} KB"
)
# 显示原始文本
self.text_original.delete(1.0, tk.END)
self.text_original.insert(1.0, self.analyzer.original_text)
# 显示清洁文本
self.text_cleaned.delete(1.0, tk.END)
self.text_cleaned.insert(1.0, self.analyzer.cleaned_text)
self.update_status(f"已加载文件: {os.path.basename(file_path)}")
else:
messagebox.showerror("错误", "无法打开文件")
def analyze_all(self):
"""全面分析文本"""
if not self.current_file:
messagebox.showwarning("警告", "请先打开一个文件")
return
thread = threading.Thread(target=self._analyze_all_thread)
thread.start()
def _analyze_all_thread(self):
"""在后台线程中执行全面分析"""
try:
self.update_status("正在分析...")
# 统计指标
stats = self.analyzer.get_statistics()
stats_str = self._format_dict_to_string(stats)
self.stats_text.delete(1.0, tk.END)
self.stats_text.insert(1.0, stats_str)
# 高频词汇
top_words = self.analyzer.get_top_words(20)
topwords_str = self._format_topwords_to_string(top_words)
self.topwords_text.delete(1.0, tk.END)
self.topwords_text.insert(1.0, topwords_str)
# 关键词
keywords = self.analyzer.extract_keywords(10)
keywords_str = "\n".join(
f"{i + 1}. {kw}" for i, kw in enumerate(keywords)
)
self.keywords_text.delete(1.0, tk.END)
self.keywords_text.insert(1.0, keywords_str)
# 句子分析
sentence_analysis = self.analyzer.analyze_sentence_structure()
sentence_str = self._format_dict_to_string(sentence_analysis)
self.sentence_text.delete(1.0, tk.END)
self.sentence_text.insert(1.0, sentence_str)
self.update_status("分析完成")
except Exception as e:
messagebox.showerror("错误", f"分析失败: {e}")
def show_segmentation(self):
"""显示分词结果"""
if not self.current_file:
messagebox.showwarning("警告", "请先打开一个文件")
return
# 用斜杠分隔显示分词结果
segmented = " / ".join(self.analyzer.words)
self.text_segmented.delete(1.0, tk.END)
self.text_segmented.insert(1.0, segmented)
self.update_status("分词完成")
def generate_summary(self):
"""生成文本摘要"""
if not self.current_file:
messagebox.showwarning("警告", "请先打开一个文件")
return
ratio = self.summary_ratio_var.get()
summary = self.analyzer.summarize(ratio)
self.text_summary.delete(1.0, tk.END)
self.text_summary.insert(1.0, summary)
# 计算压缩率
compression_ratio = (len(summary) / len(self.analyzer.original_text)) * 100
self.update_status(
f"摘要生成完成 (压缩率: {compression_ratio:.1f}%)"
)
def show_search_dialog(self):
"""
显示搜索对话框
这个方法创建一个新窗口,允许用户输入关键词来搜索文本。
搜索结果会显示包含关键词的行号和具体内容。
"""
if not self.current_file:
messagebox.showwarning("警告", "请先打开一个文件")
return
search_window = tk.Toplevel(self.root)
search_window.title("搜索文本")
search_window.geometry("600x400")
# 搜索框
frame_search = ttk.Frame(search_window)
frame_search.pack(fill=tk.X, padx=10, pady=10)
ttk.Label(frame_search, text="搜索关键词:").pack(side=tk.LEFT, padx=5)
search_var = tk.StringVar()
search_entry = ttk.Entry(frame_search, textvariable=search_var, width=40)
search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
# 结果显示区域
result_text = scrolledtext.ScrolledText(
search_window, wrap=tk.WORD, height=20, width=70
)
result_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
def do_search():
"""执行搜索操作"""
keyword = search_var.get().strip()
if not keyword:
messagebox.showwarning("警告", "请输入搜索关键词")
return
# 调用分析器的搜索方法
results = self.analyzer.search_words(keyword)
result_text.delete(1.0, tk.END)
if results:
result_text.insert(tk.END, f"找到 {len(results)} 个匹配结果:\n\n")
for line_num, line in results:
result_text.insert(tk.END, f"第 {line_num} 行: {line}\n\n")
else:
result_text.insert(tk.END, f"未找到包含 '{keyword}' 的内容")
# 搜索按钮
btn_search = tk.Button(
frame_search, text="搜索", command=do_search, width=10
)
btn_search.pack(side=tk.LEFT, padx=5)
# 自动焦点到搜索框
search_entry.focus()
def update_summary_ratio_label(self, value):
"""更新摘要比例标签"""
ratio = float(value)
percentage = int(ratio * 100)
self.summary_ratio_label.config(text=f"{percentage}%")
def save_results(self):
"""保存分析结果"""
if not self.current_file:
messagebox.showwarning("警告", "请先打开一个文件")
return
file_path = filedialog.asksaveasfilename(
title="保存分析结果",
defaultextension=".txt",
filetypes=[("文本文件", "*.txt"), ("JSON文件", "*.json")]
)
if file_path:
try:
if file_path.endswith('.json'):
# 保存为JSON格式
results = {
'文件': os.path.basename(self.current_file),
'统计指标': self.analyzer.get_statistics(),
'高频词汇': dict(self.analyzer.get_top_words(20)),
'关键词': self.analyzer.extract_keywords(10),
'句子分析': self.analyzer.analyze_sentence_structure(),
}
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(results, f, ensure_ascii=False, indent=2)
else:
# 保存为文本格式
with open(file_path, 'w', encoding='utf-8') as f:
f.write(f"文本分析结果报告\n")
f.write(f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"文件: {os.path.basename(self.current_file)}\n")
f.write("=" * 60 + "\n\n")
f.write("统计指标:\n")
stats = self.analyzer.get_statistics()
for key, value in stats.items():
f.write(f" {key}: {value}\n")
f.write("\n高频词汇 (Top 20):\n")
for word, freq in self.analyzer.get_top_words(20):
f.write(f" {word}: {freq}\n")
f.write("\n关键词 (Top 10):\n")
for i, kw in enumerate(self.analyzer.extract_keywords(10), 1):
f.write(f" {i}. {kw}\n")
messagebox.showinfo("成功", "结果已保存")
self.update_status("结果已保存")
except Exception as e:
messagebox.showerror("错误", f"保存失败: {e}")
def clear_all(self):
"""清空所有数据"""
if messagebox.askyesno("确认", "确定要清空所有数据吗?"):
self.analyzer = TextAnalyzer()
self.current_file = None
self.text_original.delete(1.0, tk.END)
self.text_cleaned.delete(1.0, tk.END)
self.text_segmented.delete(1.0, tk.END)
self.text_summary.delete(1.0, tk.END)
self.stats_text.delete(1.0, tk.END)
self.topwords_text.delete(1.0, tk.END)
self.keywords_text.delete(1.0, tk.END)
self.sentence_text.delete(1.0, tk.END)
self.file_label.config(text="未选择文件", foreground="gray")
self.file_size_label.config(text="")
self.update_status("已清空所有数据")
def update_status(self, message: str):
"""更新状态栏"""
self.status_var.set(message)
self.root.update()
def show_help(self):
"""显示帮助信息"""
help_text = """
高级中文自然语言处理系统 - 使用说明
核心功能:
1. 打开文件: 选择要分析的txt文本文件
2. 全面分析: 对文本进行全方位分析,包括统计、分词、词频等
3. 分词显示: 显示文本的分词结果(/ 分隔)
4. 生成摘要: 根据设定的比例生成文本摘要
5. 搜索文本: 快速查找特定关键词出现的位置
分析指标:
- 统计指标: 总字数、词数、句子数、词汇丰富度、文本熵值、文本质量分等
- 高频词汇: 出现次数最多的词汇排名
- 关键词: 使用TF-IDF思想提取的代表词汇
- 句子分析: 句子长度、复杂度、标准差等指标
操作提示:
- 摘要比例可以通过滑块调节 (10%-50%)
- 分析结果可以保存为txt或JSON格式
- 所有分析都支持中文,无需担心编码问题
- 系统支持多种编码自动检测
"""
help_window = tk.Toplevel(self.root)
help_window.title("使用说明")
help_window.geometry("600x500")
help_text_widget = scrolledtext.ScrolledText(help_window, wrap=tk.WORD)
help_text_widget.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
help_text_widget.insert(1.0, help_text)
help_text_widget.config(state=tk.DISABLED)
def show_about(self):
"""显示关于信息"""
about_text = """
高级中文自然语言处理系统
版本: 1.0
开发时间: 2024
功能特性:
✓ 完整的文本统计与分析
✓ 中文分词和词频统计
✓ 智能关键词提取
✓ 自动文本摘要生成
✓ 快速文本搜索功能
✓ 完全离线工作
系统特点:
- 支持多种编码(UTF-8、GBK、GB2312等)
- 多线程后台处理,不阻塞UI
- 分析结果支持导出为txt和JSON格式
- 专业级别的文本分析工具
隐私声明:
所有数据仅保留在本地,无需上传到云端。
无隐私泄露风险,完全安全可靠。
"""
messagebox.showinfo("关于", about_text)
def _format_dict_to_string(self, data: Dict) -> str:
"""将字典格式化为字符串"""
lines = []
for key, value in data.items():
lines.append(f"{key}: {value}")
return "\n".join(lines)
def _format_topwords_to_string(self, words: List[Tuple[str, int]]) -> str:
"""将高频词汇格式化为字符串"""
lines = []
for i, (word, freq) in enumerate(words, 1):
lines.append(f"{i:2d}. {word:10s} - {freq:4d} 次")
return "\n".join(lines)
# ==================== 程序入口 ====================
def main():
"""
程序主入口
创建tkinter根窗口并启动GUI应用。
"""
root = tk.Tk()
app = NLPAnalysisGUI(root)
root.mainloop()
if __name__ == '__main__':
main()

被折叠的 条评论
为什么被折叠?



