Browse Source

feat:增加聚合结果分析界面

ChenYL 1 year ago
parent
commit
c7cbb03d78

+ 18 - 6
README.md

@@ -1,11 +1,23 @@
 # 开发记录
 
-## 待办列表
-* 主进程进度不显示
-* 子进程显示不合理
-* 聚合速度需要进一步优化
-* 修改缓存建立方式(目前:1.5秒/个,期望:降到目前的10倍以下)
-* 修改子进程任务获取方式
+## 执行命令
+
+```commandline
+chcp 65001 && conda activate money-mining && python mining.py agg 数据目录路径
+```
+
+## PySide6配置
+PySide6 QtDesigner
+$FilePath$
+$ProjectFileDir$
+
+PySide6 UIC
+$FilePath$ -o $FileDir$\$FileNameWithoutExtension$.py
+$ProjectFileDir$
+
+PySide6 RCC
+$FileName$ -o $FileNameWithoutExtension$.py
+$ProjectFileDir$
 
 ## 开发进度
 * 2024-01-18

+ 36 - 0
src/MiningUI.py

@@ -0,0 +1,36 @@
+# -*- coding:utf-8 -*-
+from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QTabWidget, QLabel
+
+from src.ui.AggAnalyseModeAndView import AggAnalyseModeAndView
+from src.ui.TemplateFilteringModelAndView import TemplateFilteringModelAndView
+
+
+class MyWindow(QWidget):
+    def __init__(self):
+        super().__init__()
+
+        self.aggAnalyseTab = QWidget()
+        self.aggAnalyseTabLayout = QVBoxLayout()
+        self.aggAnalyseTabLayout.addWidget(AggAnalyseModeAndView())
+        self.aggAnalyseTab.setLayout(self.aggAnalyseTabLayout)
+
+        self.templateFilteringTab = QWidget()
+        self.templateFilteringTabLayout = QVBoxLayout()
+        self.templateFilteringTabLayout.addWidget(TemplateFilteringModelAndView())
+        self.templateFilteringTab.setLayout(self.templateFilteringTabLayout)
+
+        self.tab = QTabWidget()
+        self.tab.addTab(self.aggAnalyseTab, "聚合分析")
+        self.tab.addTab(self.templateFilteringTab, "模板筛选")
+
+        self.setWindowTitle("金钱挖掘")
+        self.mainLayout = QVBoxLayout()
+        self.mainLayout.addWidget(self.tab)
+        self.setLayout(self.mainLayout)
+
+
+if __name__ == "__main__":
+    app = QApplication()
+    window = MyWindow()
+    window.show()
+    app.exec()

+ 13 - 0
src/config.ini

@@ -0,0 +1,13 @@
+; 基本配置
+[path]
+; 临时文件路径
+tmpPath = ../tmp
+; 配置文件名
+aggConfig = ../tmp/aggConfig.json
+
+[java]
+jar = ./resources/money-mining-1.0-jar-with-dependencies.jar
+
+
+
+

+ 1 - 1
src/mining.py

@@ -1,7 +1,7 @@
 # -*- coding:utf-8 -*-
 import sys
 
-from agg import agg_word, agg_process
+from agg import agg_word
 
 
 def main(args: list):

+ 117 - 0
src/ui/AggAnalyseModeAndView.py

@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+import configparser
+import os.path
+
+from PySide6.QtCore import Qt, QEvent
+from PySide6.QtGui import QFont, QKeyEvent
+from PySide6.QtWidgets import QWidget, QFileDialog, QMessageBox
+
+from src import utils
+from src.ui.AggAnalyseView import Ui_Form
+
+
+class AggAnalyseModeAndView(QWidget, Ui_Form):
+    def __init__(self, parent=None):
+        super(AggAnalyseModeAndView, self).__init__(parent)
+        self.totalNum = 0
+        self.contentDict = dict()
+        self.setupUi(self)
+        self.bind()
+        # 设置列表字体大小
+        font = QFont()
+        font.setPointSize(16)
+        self.contentList.setFont(font)
+
+        # 获取当前脚本所在的目录
+        current_path = os.path.dirname(os.path.abspath(__file__))
+        # 获取当前脚本所在的项目根目录
+        root_path = os.path.dirname(current_path)
+        conf = configparser.ConfigParser()
+        conf.read(os.path.join(root_path, "config.ini"), encoding="UTF-8")
+        # 获取历史使用记录
+        self.configPath = conf['path']['aggConfig']
+        self.config = utils.load_json(self.configPath)
+        if self.config and self.config['targetFilePath']:
+            self.targetFilePath.setText(self.config['targetFilePath'])
+        self.load()
+
+    def bind(self):
+        self.selectFileBtn.clicked.connect(self.selectFile)
+        self.loadBtn.clicked.connect(self.load)
+        self.prevBtn.clicked.connect(self.prev)
+        self.nextBtn.clicked.connect(self.next)
+
+    def selectFile(self):
+        file_path, file_type = QFileDialog.getOpenFileName(self, "选择文件")
+        if not file_path:
+            return
+        if not os.path.isfile(file_path) or not file_path.endswith(".txt"):
+            QMessageBox.warning(self, "操作提示", "选择的文件不是文本文件")
+            return
+
+        self.targetFilePath.setText(file_path)
+        self.config['isFileExist'] = True
+        self.config['targetFilePath'] = file_path
+        self.load(True)
+
+    def load(self, isResetIndex: bool = False):
+        if not self.config['isFileExist']:
+            QMessageBox.warning(self, "输入提示", "请选择待分析文件")
+            return
+
+        # 重置位置
+        if isResetIndex:
+            self.config['currentIndex'] = 1
+
+        # 加载文件
+        index, count, tmpLines = 0, 0, []
+        with open(self.config['targetFilePath'], "r", encoding="UTF-8") as fr:
+            for line in fr.readlines():
+                if line.startswith("\n"):
+                    if tmpLines:
+                        if len(tmpLines) > self.filterSizeInput.value():
+                            index = index + 1
+                            self.contentDict[index] = {
+                                "count": count,
+                                "contentLines": tmpLines
+                            }
+                    tmpLines = []
+                    count = 0
+                else:
+                    count = count + 1
+                    tmpLines.append(utils.remove_line_break(line))
+
+        self.totalNum = len(self.contentDict)
+        self.loadData()
+
+    def prev(self):
+        self.loadData(-1)
+
+    def next(self):
+        self.loadData(1)
+
+    def loadData(self, direction: int = 0):
+        """
+        加载数据
+        :param direction: 显示位置:-1-往前;0-不变;1-往后
+        :return:
+        """
+        currentIndex = self.config['currentIndex']
+        if (direction < 0 and currentIndex == 1) or (direction > 0 and currentIndex == self.totalNum):
+            return
+        self.config['currentIndex'] = self.config['currentIndex'] + direction
+
+        self.contentList.clear()
+        self.contentList.addItems(self.contentDict[currentIndex]["contentLines"])
+        self.msg.setText("总数量:%d,当前位置:%d,数量:%d" % (
+            self.totalNum, currentIndex, self.contentDict[currentIndex]["count"]))
+        # 保存历史使用记录
+        utils.saveJson(self.configPath, self.config)
+
+    def keyPressEvent(self, event):
+        if event.key() == Qt.Key.Key_Left:
+            self.prev()
+        elif event.key() == Qt.Key.Key_Right:
+            self.next()
+        else:
+            super().keyPressEvent(event)

+ 106 - 0
src/ui/AggAnalyseView.py

@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'AggAnalyseView.ui'
+##
+## Created by: Qt User Interface Compiler version 6.5.1
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+    QMetaObject, QObject, QPoint, QRect,
+    QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+    QFont, QFontDatabase, QGradient, QIcon,
+    QImage, QKeySequence, QLinearGradient, QPainter,
+    QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QAbstractItemView, QApplication, QGridLayout, QLabel,
+    QLayout, QLineEdit, QListWidget, QListWidgetItem,
+    QPushButton, QSizePolicy, QSpinBox, QVBoxLayout,
+    QWidget)
+
+class Ui_Form(object):
+    def setupUi(self, Form):
+        if not Form.objectName():
+            Form.setObjectName(u"Form")
+        Form.resize(1675, 904)
+        self.verticalLayout = QVBoxLayout(Form)
+        self.verticalLayout.setObjectName(u"verticalLayout")
+        self.gridLayout = QGridLayout()
+        self.gridLayout.setObjectName(u"gridLayout")
+        self.gridLayout.setSizeConstraint(QLayout.SetMaximumSize)
+        self.prevBtn = QPushButton(Form)
+        self.prevBtn.setObjectName(u"prevBtn")
+
+        self.gridLayout.addWidget(self.prevBtn, 2, 0, 1, 1)
+
+        self.loadBtn = QPushButton(Form)
+        self.loadBtn.setObjectName(u"loadBtn")
+
+        self.gridLayout.addWidget(self.loadBtn, 1, 3, 1, 1)
+
+        self.targetFilePath = QLineEdit(Form)
+        self.targetFilePath.setObjectName(u"targetFilePath")
+
+        self.gridLayout.addWidget(self.targetFilePath, 0, 2, 1, 1)
+
+        self.label_2 = QLabel(Form)
+        self.label_2.setObjectName(u"label_2")
+
+        self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)
+
+        self.selectFileBtn = QPushButton(Form)
+        self.selectFileBtn.setObjectName(u"selectFileBtn")
+
+        self.gridLayout.addWidget(self.selectFileBtn, 0, 3, 1, 1)
+
+        self.nextBtn = QPushButton(Form)
+        self.nextBtn.setObjectName(u"nextBtn")
+
+        self.gridLayout.addWidget(self.nextBtn, 2, 4, 1, 1)
+
+        self.label = QLabel(Form)
+        self.label.setObjectName(u"label")
+
+        self.gridLayout.addWidget(self.label, 1, 1, 1, 1)
+
+        self.filterSizeInput = QSpinBox(Form)
+        self.filterSizeInput.setObjectName(u"filterSizeInput")
+        self.filterSizeInput.setValue(2)
+
+        self.gridLayout.addWidget(self.filterSizeInput, 1, 2, 1, 1)
+
+        self.msg = QLabel(Form)
+        self.msg.setObjectName(u"msg")
+
+        self.gridLayout.addWidget(self.msg, 3, 1, 1, 3)
+
+        self.contentList = QListWidget(Form)
+        self.contentList.setObjectName(u"contentList")
+        self.contentList.setEnabled(True)
+        self.contentList.setFocusPolicy(Qt.StrongFocus)
+        self.contentList.setSelectionMode(QAbstractItemView.SingleSelection)
+
+        self.gridLayout.addWidget(self.contentList, 2, 1, 1, 3)
+
+
+        self.verticalLayout.addLayout(self.gridLayout)
+
+
+        self.retranslateUi(Form)
+
+        QMetaObject.connectSlotsByName(Form)
+    # setupUi
+
+    def retranslateUi(self, Form):
+        Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
+        self.prevBtn.setText(QCoreApplication.translate("Form", u"\u4e0a\u4e00\u4e2a", None))
+        self.loadBtn.setText(QCoreApplication.translate("Form", u"\u52a0\u8f7d", None))
+        self.label_2.setText(QCoreApplication.translate("Form", u"\u76ee\u6807\u6587\u4ef6", None))
+        self.selectFileBtn.setText(QCoreApplication.translate("Form", u"\u9009\u62e9\u6587\u4ef6", None))
+        self.nextBtn.setText(QCoreApplication.translate("Form", u"\u4e0b\u4e00\u4e2a", None))
+        self.label.setText(QCoreApplication.translate("Form", u"\u8fc7\u6ee4\u805a\u5408\u5927\u5c0f", None))
+        self.msg.setText(QCoreApplication.translate("Form", u"TextLabel", None))
+    # retranslateUi
+

+ 100 - 0
src/ui/AggAnalyseView.ui

@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Form</class>
+ <widget class="QWidget" name="Form">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1675</width>
+    <height>904</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <property name="sizeConstraint">
+      <enum>QLayout::SetMaximumSize</enum>
+     </property>
+     <item row="2" column="0">
+      <widget class="QPushButton" name="prevBtn">
+       <property name="text">
+        <string>上一个</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="3">
+      <widget class="QPushButton" name="loadBtn">
+       <property name="text">
+        <string>加载</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLineEdit" name="targetFilePath"/>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>目标文件</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="3">
+      <widget class="QPushButton" name="selectFileBtn">
+       <property name="text">
+        <string>选择文件</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="4">
+      <widget class="QPushButton" name="nextBtn">
+       <property name="text">
+        <string>下一个</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>过滤聚合大小</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="2">
+      <widget class="QSpinBox" name="filterSizeInput">
+       <property name="value">
+        <number>2</number>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1" colspan="3">
+      <widget class="QLabel" name="msg">
+       <property name="text">
+        <string>TextLabel</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1" colspan="3">
+      <widget class="QListWidget" name="contentList">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::ClickFocus</enum>
+       </property>
+       <property name="selectionMode">
+        <enum>QAbstractItemView::SingleSelection</enum>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 183 - 0
src/ui/TemplateFilteringModelAndView.py

@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+import json
+import os.path
+import re
+from functools import partial
+
+from PySide6.QtWidgets import QMessageBox, QFileDialog, QWidget, QLineEdit, QPushButton, \
+    QTextEdit, QTextBrowser
+
+from src.ui.TemplateFilteringView import Ui_Form
+
+category_pattern = re.compile(r'\[类别\]')
+digit_pattern = re.compile(r'\[数字\]')
+english_pattern = re.compile(r'\[字母\]')
+
+CHARACTER_FILTER_STR = "[字母]"
+DIGIT_FILTER_STR = "[数字]"
+CATEGORY_FILTER_STR = "[类别]"
+
+CONFIG_FILE_PATH = "../tmp/config.json"
+CONFIG_ITEM_LAST_SELECT_FILE_PATH = "lastSelectFilePath"
+
+
+class TemplateFilteringModelAndView(QWidget, Ui_Form):
+
+    def __init__(self, parent=None):
+        super(TemplateFilteringModelAndView, self).__init__(parent)
+        self.setupUi(self)
+        self.bind()
+        self.loadConfig()
+
+    def bind(self):
+        self.toolDict = {
+            self.firstDigitBtn.objectName(): self.firstKeyBox,
+            self.firstCategoryBtn.objectName(): self.firstKeyBox,
+            self.firstCharacterBtn.objectName(): self.firstKeyBox,
+            self.secondDigitBtn.objectName(): self.secondKeyBox,
+            self.secondCategoryBtn.objectName(): self.secondKeyBox,
+            self.secondCharacterBtn.objectName(): self.secondKeyBox,
+            self.threeDigitBtn.objectName(): self.threeKeyBox,
+            self.threeCategoryBtn.objectName(): self.threeKeyBox,
+            self.threeCharacterBtn.objectName(): self.threeKeyBox,
+            self.fourDigitBtn.objectName(): self.fourKeyBox,
+            self.fourCategoryBtn.objectName(): self.fourKeyBox,
+            self.fourCharacterBtn.objectName(): self.fourKeyBox
+        }
+        self.resultDict = {
+            self.firstFilterBtn.objectName(): (
+            self.firstKeyBox, self.firstCategoryBox, self.firstResultBox, None, self.result_label_1),
+            self.secondFilterBtn.objectName(): (
+            self.secondKeyBox, self.secondCategoryBox, self.secondResultBox, self.firstResultBox, self.result_label_2),
+            self.threeFilterBtn.objectName(): (
+            self.threeKeyBox, self.threeCategoryBox, self.threeResultBox, self.secondResultBox, self.result_label_3),
+            self.fourFilterBtn.objectName(): (
+            self.fourKeyBox, self.fourCategoryBox, self.fourResultBox, self.threeResultBox, self.result_label_4)
+        }
+
+        self.fileBtn.clicked.connect(self.selectFile)
+
+        self.firstCategoryBtn.clicked.connect(partial(self.add_filter_str, self.firstCategoryBtn, CATEGORY_FILTER_STR))
+        self.firstDigitBtn.clicked.connect(partial(self.add_filter_str, self.firstDigitBtn, DIGIT_FILTER_STR))
+        self.firstCharacterBtn.clicked.connect(
+            partial(self.add_filter_str, self.firstCharacterBtn, CHARACTER_FILTER_STR))
+        self.firstFilterBtn.clicked.connect(partial(self.submit, self.firstFilterBtn))
+
+        self.secondCategoryBtn.clicked.connect(
+            partial(self.add_filter_str, self.secondCategoryBtn, CATEGORY_FILTER_STR))
+        self.secondDigitBtn.clicked.connect(partial(self.add_filter_str, self.secondDigitBtn, DIGIT_FILTER_STR))
+        self.secondCharacterBtn.clicked.connect(
+            partial(self.add_filter_str, self.secondCharacterBtn, CHARACTER_FILTER_STR))
+        self.secondFilterBtn.clicked.connect(partial(self.submit, self.secondFilterBtn))
+
+        self.threeCategoryBtn.clicked.connect(partial(self.add_filter_str, self.threeCategoryBtn, CATEGORY_FILTER_STR))
+        self.threeDigitBtn.clicked.connect(partial(self.add_filter_str, self.threeDigitBtn, DIGIT_FILTER_STR))
+        self.threeCharacterBtn.clicked.connect(
+            partial(self.add_filter_str, self.threeCharacterBtn, CHARACTER_FILTER_STR))
+        self.threeFilterBtn.clicked.connect(partial(self.submit, self.threeFilterBtn))
+
+        self.fourCategoryBtn.clicked.connect(partial(self.add_filter_str, self.fourCategoryBtn, CATEGORY_FILTER_STR))
+        self.fourDigitBtn.clicked.connect(partial(self.add_filter_str, self.fourDigitBtn, DIGIT_FILTER_STR))
+        self.fourCharacterBtn.clicked.connect(partial(self.add_filter_str, self.fourCharacterBtn, CHARACTER_FILTER_STR))
+        self.fourFilterBtn.clicked.connect(partial(self.submit, self.fourFilterBtn))
+
+    def loadConfig(self):
+        if os.path.isfile(CONFIG_FILE_PATH):
+            with open(CONFIG_FILE_PATH, 'r', encoding='utf-8') as f:
+                config = json.loads(f.read())
+                self.filePathBox.setText(config[CONFIG_ITEM_LAST_SELECT_FILE_PATH])
+
+    def selectFile(self):
+        file_path, file_type = QFileDialog.getOpenFileName(self, "选择文件")
+        with open(CONFIG_FILE_PATH, 'w', encoding='utf-8') as f:
+            f.write(json.dumps({CONFIG_ITEM_LAST_SELECT_FILE_PATH: file_path}))
+        self.filePathBox.setText(file_path)
+
+    def add_filter_str(self, btn_widget: QPushButton, filter_text):
+        key_box = self.toolDict[btn_widget.objectName()]
+        key_box.setText(key_box.text() + filter_text)
+
+    def submit(self, filter_btn: QPushButton):
+
+        key_box, category_box, result_box, parent_result_box, result_label = self.resultDict[filter_btn.objectName()]
+
+        if not self.check(key_box, category_box, parent_result_box):
+            return
+
+        before_filter_cnt, after_filter_cnt, filter_result_arr = self.deal(key_box, category_box, parent_result_box)
+        result_label.setText("提取结果:原始数据%s条,筛选后%s条" % (before_filter_cnt, after_filter_cnt))
+        result_box.setText("\n".join(filter_result_arr))
+
+    def check(self, key_box: QLineEdit, category_box: QTextEdit, parent_result_box: QTextBrowser):
+        key_text = key_box.text()
+        if len(key_text) == 0:
+            QMessageBox.warning(self, "输入提示", "请输入待筛选关键词")
+            return False
+
+        cnt = 0
+        for pattern in [category_pattern, digit_pattern, english_pattern]:
+            if pattern.search(key_text) is not None:
+                cnt = cnt + 1
+            if cnt > 1:
+                QMessageBox.warning(self, "提示", "一次只能使用一种正则筛选项")
+                return False
+
+        category_text = category_box.toPlainText()
+        if category_pattern.search(key_text) is not None and len(category_text) == 0:
+            QMessageBox.warning(self, "提示", "使用类别筛选,请输入待筛选的类别关键词")
+            return False
+
+        if parent_result_box is None:
+            file_path = self.filePathBox.text()
+            if len(file_path) == 0:
+                QMessageBox.warning(self, "提示", "请选择带筛选文件")
+                return False
+        elif len(parent_result_box.toPlainText()) == 0:
+            QMessageBox.warning(self, "提示", "上级结果中没有数据")
+            return False
+
+        return True
+
+    def deal(self, key_box: QLineEdit, category_box: QTextEdit, parent_result_box: QTextBrowser):
+        key_text = key_box.text()
+
+        parent_key_arr = None
+        if parent_result_box is None:
+            with open(self.filePathBox.text(), 'r', encoding='utf-8') as f:
+                parent_key_arr = [content.replace("\n", "") for content in f.readlines()]
+        else:
+            parent_key_arr = parent_result_box.toPlainText().split("\n")
+
+        filter_result_arr = None
+        if category_pattern.search(key_text) is not None:
+            filter_result_arr = set()
+            categoryKeyArray = category_box.toPlainText().splitlines()
+            for categoryKey in categoryKeyArray:
+                filter_result_arr.update(self.filter(parent_key_arr, key_text, "类别", categoryKey))
+        elif digit_pattern.search(key_text) is not None:
+            filter_result_arr = self.filter(parent_key_arr, key_text, "数字", "0-9")
+        elif english_pattern.search(key_text) is not None:
+            filter_result_arr = self.filter(parent_key_arr, key_text, "字母", "A-Za-z")
+        else:
+            filter_result_arr = self.filter(parent_key_arr, key_text)
+
+        return len(parent_key_arr), len(filter_result_arr), filter_result_arr
+
+    def filter(self, originArray, inputText, oldStr=None, newStr=None):
+        resultArray = []
+        key_pattern = None
+        filter_pattern = None
+        if oldStr is not None and len(oldStr) > 0:
+            key_pattern = re.compile(inputText.replace("[{}]".format(oldStr), ""))
+        else:
+            key_pattern = re.compile(inputText)
+        if newStr is not None and len(newStr) > 0:
+            filter_pattern = re.compile("[{}]".format(newStr))
+        for originKey in originArray:
+            if key_pattern.search(originKey) is not None:
+                if filter_pattern is not None:
+                    if filter_pattern.search(originKey) is not None:
+                        resultArray.append(originKey)
+                else:
+                    resultArray.append(originKey)
+        return resultArray

+ 330 - 0
src/ui/TemplateFilteringView.py

@@ -0,0 +1,330 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'TemplateFilteringView.ui'
+##
+## Created by: Qt User Interface Compiler version 6.5.1
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+    QMetaObject, QObject, QPoint, QRect,
+    QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+    QFont, QFontDatabase, QGradient, QIcon,
+    QImage, QKeySequence, QLinearGradient, QPainter,
+    QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QApplication, QHBoxLayout, QLabel, QLayout,
+    QLineEdit, QPushButton, QSizePolicy, QTextBrowser,
+    QTextEdit, QVBoxLayout, QWidget)
+
+class Ui_Form(object):
+    def setupUi(self, Form):
+        if not Form.objectName():
+            Form.setObjectName(u"Form")
+        Form.setWindowModality(Qt.NonModal)
+        Form.setEnabled(True)
+        Form.resize(1546, 514)
+        Form.setMinimumSize(QSize(800, 400))
+        self.verticalLayout_2 = QVBoxLayout(Form)
+        self.verticalLayout_2.setObjectName(u"verticalLayout_2")
+        self.horizontalLayout_2 = QHBoxLayout()
+        self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
+        self.filePathBox = QLineEdit(Form)
+        self.filePathBox.setObjectName(u"filePathBox")
+        self.filePathBox.setEnabled(False)
+
+        self.horizontalLayout_2.addWidget(self.filePathBox)
+
+        self.fileBtn = QPushButton(Form)
+        self.fileBtn.setObjectName(u"fileBtn")
+
+        self.horizontalLayout_2.addWidget(self.fileBtn)
+
+
+        self.verticalLayout_2.addLayout(self.horizontalLayout_2)
+
+        self.horizontalLayout_6 = QHBoxLayout()
+        self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
+        self.horizontalLayout_6.setSizeConstraint(QLayout.SetDefaultConstraint)
+        self.verticalLayout = QVBoxLayout()
+        self.verticalLayout.setObjectName(u"verticalLayout")
+        self.firstKeyBox = QLineEdit(Form)
+        self.firstKeyBox.setObjectName(u"firstKeyBox")
+
+        self.verticalLayout.addWidget(self.firstKeyBox)
+
+        self.horizontalLayout = QHBoxLayout()
+        self.horizontalLayout.setObjectName(u"horizontalLayout")
+        self.firstDigitBtn = QPushButton(Form)
+        self.firstDigitBtn.setObjectName(u"firstDigitBtn")
+
+        self.horizontalLayout.addWidget(self.firstDigitBtn)
+
+        self.firstCategoryBtn = QPushButton(Form)
+        self.firstCategoryBtn.setObjectName(u"firstCategoryBtn")
+
+        self.horizontalLayout.addWidget(self.firstCategoryBtn)
+
+        self.firstCharacterBtn = QPushButton(Form)
+        self.firstCharacterBtn.setObjectName(u"firstCharacterBtn")
+
+        self.horizontalLayout.addWidget(self.firstCharacterBtn)
+
+        self.firstFilterBtn = QPushButton(Form)
+        self.firstFilterBtn.setObjectName(u"firstFilterBtn")
+
+        self.horizontalLayout.addWidget(self.firstFilterBtn)
+
+
+        self.verticalLayout.addLayout(self.horizontalLayout)
+
+        self.label_2 = QLabel(Form)
+        self.label_2.setObjectName(u"label_2")
+
+        self.verticalLayout.addWidget(self.label_2)
+
+        self.firstCategoryBox = QTextEdit(Form)
+        self.firstCategoryBox.setObjectName(u"firstCategoryBox")
+        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.firstCategoryBox.sizePolicy().hasHeightForWidth())
+        self.firstCategoryBox.setSizePolicy(sizePolicy)
+
+        self.verticalLayout.addWidget(self.firstCategoryBox)
+
+        self.result_label_1 = QLabel(Form)
+        self.result_label_1.setObjectName(u"result_label_1")
+
+        self.verticalLayout.addWidget(self.result_label_1)
+
+        self.firstResultBox = QTextBrowser(Form)
+        self.firstResultBox.setObjectName(u"firstResultBox")
+        sizePolicy.setHeightForWidth(self.firstResultBox.sizePolicy().hasHeightForWidth())
+        self.firstResultBox.setSizePolicy(sizePolicy)
+
+        self.verticalLayout.addWidget(self.firstResultBox)
+
+        self.verticalLayout.setStretch(3, 1)
+        self.verticalLayout.setStretch(5, 5)
+
+        self.horizontalLayout_6.addLayout(self.verticalLayout)
+
+        self.verticalLayout_4 = QVBoxLayout()
+        self.verticalLayout_4.setObjectName(u"verticalLayout_4")
+        self.secondKeyBox = QLineEdit(Form)
+        self.secondKeyBox.setObjectName(u"secondKeyBox")
+
+        self.verticalLayout_4.addWidget(self.secondKeyBox)
+
+        self.horizontalLayout_3 = QHBoxLayout()
+        self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
+        self.secondDigitBtn = QPushButton(Form)
+        self.secondDigitBtn.setObjectName(u"secondDigitBtn")
+
+        self.horizontalLayout_3.addWidget(self.secondDigitBtn)
+
+        self.secondCategoryBtn = QPushButton(Form)
+        self.secondCategoryBtn.setObjectName(u"secondCategoryBtn")
+
+        self.horizontalLayout_3.addWidget(self.secondCategoryBtn)
+
+        self.secondCharacterBtn = QPushButton(Form)
+        self.secondCharacterBtn.setObjectName(u"secondCharacterBtn")
+
+        self.horizontalLayout_3.addWidget(self.secondCharacterBtn)
+
+        self.secondFilterBtn = QPushButton(Form)
+        self.secondFilterBtn.setObjectName(u"secondFilterBtn")
+
+        self.horizontalLayout_3.addWidget(self.secondFilterBtn)
+
+
+        self.verticalLayout_4.addLayout(self.horizontalLayout_3)
+
+        self.label_4 = QLabel(Form)
+        self.label_4.setObjectName(u"label_4")
+
+        self.verticalLayout_4.addWidget(self.label_4)
+
+        self.secondCategoryBox = QTextEdit(Form)
+        self.secondCategoryBox.setObjectName(u"secondCategoryBox")
+        sizePolicy.setHeightForWidth(self.secondCategoryBox.sizePolicy().hasHeightForWidth())
+        self.secondCategoryBox.setSizePolicy(sizePolicy)
+
+        self.verticalLayout_4.addWidget(self.secondCategoryBox)
+
+        self.result_label_2 = QLabel(Form)
+        self.result_label_2.setObjectName(u"result_label_2")
+
+        self.verticalLayout_4.addWidget(self.result_label_2)
+
+        self.secondResultBox = QTextBrowser(Form)
+        self.secondResultBox.setObjectName(u"secondResultBox")
+
+        self.verticalLayout_4.addWidget(self.secondResultBox)
+
+        self.verticalLayout_4.setStretch(3, 1)
+        self.verticalLayout_4.setStretch(5, 5)
+
+        self.horizontalLayout_6.addLayout(self.verticalLayout_4)
+
+        self.verticalLayout_7 = QVBoxLayout()
+        self.verticalLayout_7.setObjectName(u"verticalLayout_7")
+        self.threeKeyBox = QLineEdit(Form)
+        self.threeKeyBox.setObjectName(u"threeKeyBox")
+
+        self.verticalLayout_7.addWidget(self.threeKeyBox)
+
+        self.horizontalLayout_4 = QHBoxLayout()
+        self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
+        self.threeDigitBtn = QPushButton(Form)
+        self.threeDigitBtn.setObjectName(u"threeDigitBtn")
+
+        self.horizontalLayout_4.addWidget(self.threeDigitBtn)
+
+        self.threeCategoryBtn = QPushButton(Form)
+        self.threeCategoryBtn.setObjectName(u"threeCategoryBtn")
+
+        self.horizontalLayout_4.addWidget(self.threeCategoryBtn)
+
+        self.threeCharacterBtn = QPushButton(Form)
+        self.threeCharacterBtn.setObjectName(u"threeCharacterBtn")
+
+        self.horizontalLayout_4.addWidget(self.threeCharacterBtn)
+
+        self.threeFilterBtn = QPushButton(Form)
+        self.threeFilterBtn.setObjectName(u"threeFilterBtn")
+
+        self.horizontalLayout_4.addWidget(self.threeFilterBtn)
+
+
+        self.verticalLayout_7.addLayout(self.horizontalLayout_4)
+
+        self.label_6 = QLabel(Form)
+        self.label_6.setObjectName(u"label_6")
+
+        self.verticalLayout_7.addWidget(self.label_6)
+
+        self.threeCategoryBox = QTextEdit(Form)
+        self.threeCategoryBox.setObjectName(u"threeCategoryBox")
+        sizePolicy.setHeightForWidth(self.threeCategoryBox.sizePolicy().hasHeightForWidth())
+        self.threeCategoryBox.setSizePolicy(sizePolicy)
+
+        self.verticalLayout_7.addWidget(self.threeCategoryBox)
+
+        self.result_label_3 = QLabel(Form)
+        self.result_label_3.setObjectName(u"result_label_3")
+
+        self.verticalLayout_7.addWidget(self.result_label_3)
+
+        self.threeResultBox = QTextBrowser(Form)
+        self.threeResultBox.setObjectName(u"threeResultBox")
+
+        self.verticalLayout_7.addWidget(self.threeResultBox)
+
+        self.verticalLayout_7.setStretch(3, 1)
+        self.verticalLayout_7.setStretch(5, 5)
+
+        self.horizontalLayout_6.addLayout(self.verticalLayout_7)
+
+        self.verticalLayout_10 = QVBoxLayout()
+        self.verticalLayout_10.setObjectName(u"verticalLayout_10")
+        self.fourKeyBox = QLineEdit(Form)
+        self.fourKeyBox.setObjectName(u"fourKeyBox")
+
+        self.verticalLayout_10.addWidget(self.fourKeyBox)
+
+        self.horizontalLayout_5 = QHBoxLayout()
+        self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
+        self.fourDigitBtn = QPushButton(Form)
+        self.fourDigitBtn.setObjectName(u"fourDigitBtn")
+
+        self.horizontalLayout_5.addWidget(self.fourDigitBtn)
+
+        self.fourCategoryBtn = QPushButton(Form)
+        self.fourCategoryBtn.setObjectName(u"fourCategoryBtn")
+
+        self.horizontalLayout_5.addWidget(self.fourCategoryBtn)
+
+        self.fourCharacterBtn = QPushButton(Form)
+        self.fourCharacterBtn.setObjectName(u"fourCharacterBtn")
+
+        self.horizontalLayout_5.addWidget(self.fourCharacterBtn)
+
+        self.fourFilterBtn = QPushButton(Form)
+        self.fourFilterBtn.setObjectName(u"fourFilterBtn")
+
+        self.horizontalLayout_5.addWidget(self.fourFilterBtn)
+
+
+        self.verticalLayout_10.addLayout(self.horizontalLayout_5)
+
+        self.label_8 = QLabel(Form)
+        self.label_8.setObjectName(u"label_8")
+
+        self.verticalLayout_10.addWidget(self.label_8)
+
+        self.fourCategoryBox = QTextEdit(Form)
+        self.fourCategoryBox.setObjectName(u"fourCategoryBox")
+        sizePolicy.setHeightForWidth(self.fourCategoryBox.sizePolicy().hasHeightForWidth())
+        self.fourCategoryBox.setSizePolicy(sizePolicy)
+
+        self.verticalLayout_10.addWidget(self.fourCategoryBox)
+
+        self.result_label_4 = QLabel(Form)
+        self.result_label_4.setObjectName(u"result_label_4")
+
+        self.verticalLayout_10.addWidget(self.result_label_4)
+
+        self.fourResultBox = QTextBrowser(Form)
+        self.fourResultBox.setObjectName(u"fourResultBox")
+
+        self.verticalLayout_10.addWidget(self.fourResultBox)
+
+        self.verticalLayout_10.setStretch(3, 1)
+        self.verticalLayout_10.setStretch(5, 5)
+
+        self.horizontalLayout_6.addLayout(self.verticalLayout_10)
+
+
+        self.verticalLayout_2.addLayout(self.horizontalLayout_6)
+
+
+        self.retranslateUi(Form)
+
+        QMetaObject.connectSlotsByName(Form)
+    # setupUi
+
+    def retranslateUi(self, Form):
+        Form.setWindowTitle(QCoreApplication.translate("Form", u"\u6570\u636e\u7b5b\u9009", None))
+        self.filePathBox.setPlaceholderText(QCoreApplication.translate("Form", u"\u8bf7\u9009\u62e9\u6587\u4ef6", None))
+        self.fileBtn.setText(QCoreApplication.translate("Form", u"\u6587\u4ef6\u9009\u62e9", None))
+        self.firstDigitBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u6570\u5b57", None))
+        self.firstCategoryBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u7c7b\u522b", None))
+        self.firstCharacterBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u82f1\u6587", None))
+        self.firstFilterBtn.setText(QCoreApplication.translate("Form", u"\u63d0\u53d6", None))
+        self.label_2.setText(QCoreApplication.translate("Form", u"\u81ea\u5b9a\u4e49\u7c7b\u522b\u8bcd", None))
+        self.result_label_1.setText(QCoreApplication.translate("Form", u"\u63d0\u53d6\u7ed3\u679c", None))
+        self.secondDigitBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u6570\u5b57", None))
+        self.secondCategoryBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u7c7b\u522b", None))
+        self.secondCharacterBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u82f1\u6587", None))
+        self.secondFilterBtn.setText(QCoreApplication.translate("Form", u"\u63d0\u53d6", None))
+        self.label_4.setText(QCoreApplication.translate("Form", u"\u81ea\u5b9a\u4e49\u7c7b\u522b\u8bcd", None))
+        self.result_label_2.setText(QCoreApplication.translate("Form", u"\u63d0\u53d6\u7ed3\u679c", None))
+        self.threeDigitBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u6570\u5b57", None))
+        self.threeCategoryBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u7c7b\u522b", None))
+        self.threeCharacterBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u82f1\u6587", None))
+        self.threeFilterBtn.setText(QCoreApplication.translate("Form", u"\u63d0\u53d6", None))
+        self.label_6.setText(QCoreApplication.translate("Form", u"\u81ea\u5b9a\u4e49\u7c7b\u522b\u8bcd", None))
+        self.result_label_3.setText(QCoreApplication.translate("Form", u"\u63d0\u53d6\u7ed3\u679c", None))
+        self.fourDigitBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u6570\u5b57", None))
+        self.fourCategoryBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u7c7b\u522b", None))
+        self.fourCharacterBtn.setText(QCoreApplication.translate("Form", u"\u63d2\u5165\u82f1\u6587", None))
+        self.fourFilterBtn.setText(QCoreApplication.translate("Form", u"\u63d0\u53d6", None))
+        self.label_8.setText(QCoreApplication.translate("Form", u"\u81ea\u5b9a\u4e49\u7c7b\u522b\u8bcd", None))
+        self.result_label_4.setText(QCoreApplication.translate("Form", u"\u63d0\u53d6\u7ed3\u679c", None))
+    # retranslateUi
+

+ 332 - 0
src/ui/TemplateFilteringView.ui

@@ -0,0 +1,332 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Form</class>
+ <widget class="QWidget" name="Form">
+  <property name="windowModality">
+   <enum>Qt::NonModal</enum>
+  </property>
+  <property name="enabled">
+   <bool>true</bool>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1546</width>
+    <height>514</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>800</width>
+    <height>400</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>数据筛选</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QLineEdit" name="filePathBox">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="placeholderText">
+        <string>请选择文件</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="fileBtn">
+       <property name="text">
+        <string>文件选择</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_6">
+     <property name="sizeConstraint">
+      <enum>QLayout::SetDefaultConstraint</enum>
+     </property>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,1,0,5">
+       <item>
+        <widget class="QLineEdit" name="firstKeyBox"/>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <item>
+          <widget class="QPushButton" name="firstDigitBtn">
+           <property name="text">
+            <string>插入数字</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="firstCategoryBtn">
+           <property name="text">
+            <string>插入类别</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="firstCharacterBtn">
+           <property name="text">
+            <string>插入英文</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="firstFilterBtn">
+           <property name="text">
+            <string>提取</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_2">
+         <property name="text">
+          <string>自定义类别词</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTextEdit" name="firstCategoryBox">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="result_label_1">
+         <property name="text">
+          <string>提取结果</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTextBrowser" name="firstResultBox">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,0,1,0,5">
+       <item>
+        <widget class="QLineEdit" name="secondKeyBox"/>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <item>
+          <widget class="QPushButton" name="secondDigitBtn">
+           <property name="text">
+            <string>插入数字</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="secondCategoryBtn">
+           <property name="text">
+            <string>插入类别</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="secondCharacterBtn">
+           <property name="text">
+            <string>插入英文</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="secondFilterBtn">
+           <property name="text">
+            <string>提取</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_4">
+         <property name="text">
+          <string>自定义类别词</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTextEdit" name="secondCategoryBox">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="result_label_2">
+         <property name="text">
+          <string>提取结果</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTextBrowser" name="secondResultBox"/>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout_7" stretch="0,0,0,1,0,5">
+       <item>
+        <widget class="QLineEdit" name="threeKeyBox"/>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <item>
+          <widget class="QPushButton" name="threeDigitBtn">
+           <property name="text">
+            <string>插入数字</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="threeCategoryBtn">
+           <property name="text">
+            <string>插入类别</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="threeCharacterBtn">
+           <property name="text">
+            <string>插入英文</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="threeFilterBtn">
+           <property name="text">
+            <string>提取</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_6">
+         <property name="text">
+          <string>自定义类别词</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTextEdit" name="threeCategoryBox">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="result_label_3">
+         <property name="text">
+          <string>提取结果</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTextBrowser" name="threeResultBox"/>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout_10" stretch="0,0,0,1,0,5">
+       <item>
+        <widget class="QLineEdit" name="fourKeyBox"/>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_5">
+         <item>
+          <widget class="QPushButton" name="fourDigitBtn">
+           <property name="text">
+            <string>插入数字</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="fourCategoryBtn">
+           <property name="text">
+            <string>插入类别</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="fourCharacterBtn">
+           <property name="text">
+            <string>插入英文</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="fourFilterBtn">
+           <property name="text">
+            <string>提取</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QLabel" name="label_8">
+         <property name="text">
+          <string>自定义类别词</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTextEdit" name="fourCategoryBox">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLabel" name="result_label_4">
+         <property name="text">
+          <string>提取结果</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTextBrowser" name="fourResultBox"/>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 0 - 0
src/ui/__init__.py


+ 25 - 0
src/utils.py

@@ -1,4 +1,5 @@
 # -*- coding:utf-8 -*-
+import json
 import math
 import os
 import pickle
@@ -105,3 +106,27 @@ def remove_line_break(line: str):
     if line:
         return line.replace("\r", "").replace("\n", "")
     return line
+
+
+def saveJson(save_path: str, save_obj: dict):
+    """
+    保存为json文件
+    :param save_path: 保存的路径
+    :param save_obj: 保存的内容对象
+    :return:
+    """
+    with open(save_path, 'w', encoding='utf-8') as f:
+        f.write(json.dumps(save_obj))
+
+
+def load_json(path: str):
+    """
+    加载json文件
+    :param path:
+    :return:
+    """
+    if os.path.exists(path) and os.path.isfile(path):
+        with open(path, 'r', encoding='utf-8') as f:
+            return json.loads(f.read())
+
+    return dict()