From 81f27ccb4cfa33517fff99c4358356ee17d92f0b Mon Sep 17 00:00:00 2001 From: codeboss <2422523675@qq.com> Date: Sun, 14 Jul 2024 23:04:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=AF=94=E5=AF=B9=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=E9=9B=8F=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/workspace.xml | 14 +- entry.py | 11 +- frame/CompareWindow.py | 56 +++++ frame/__init__.py | 0 .../__pycache__/CompareWindow.cpython-312.pyc | Bin 0 -> 3047 bytes frame/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 149 bytes parse/__pycache__/__init__.cpython-312.pyc | Bin 144 -> 149 bytes parse/__pycache__/ast_load.cpython-312.pyc | Bin 3391 -> 10141 bytes parse/ast_load.py | 215 ++++++++++++++++-- 9 files changed, 272 insertions(+), 24 deletions(-) create mode 100644 frame/CompareWindow.py create mode 100644 frame/__init__.py create mode 100644 frame/__pycache__/CompareWindow.cpython-312.pyc create mode 100644 frame/__pycache__/__init__.cpython-312.pyc diff --git a/.idea/workspace.xml b/.idea/workspace.xml index de3eb34..8001eec 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,6 +5,8 @@ + + @@ -24,9 +26,9 @@ - + { + "associatedIndex": 1 +} @@ -39,8 +41,10 @@ "keyToString": { "Python.ast_load.executor": "Debug", "Python.entry.executor": "Debug", + "RunOnceActivity.OpenProjectViewOnStart": "true", "RunOnceActivity.ShowReadmeOnStart": "true", - "git-widget-placeholder": "master" + "git-widget-placeholder": "master", + "last_opened_file_path": "D:/Projects/Python/StoryCheckTools" } }]]> @@ -75,7 +79,7 @@ - diff --git a/entry.py b/entry.py index a8fd386..2b0f420 100644 --- a/entry.py +++ b/entry.py @@ -1,8 +1,17 @@ from PyQt5.QtWidgets import QWidget, QApplication +from frame.CompareWindow import CompareWin from sys import argv from parse.ast_load import global_ast_path, AstParse tool = AstParse(global_ast_path) print(tool.generate_time()) -tool.peak_storylines() \ No newline at end of file +storys = tool.peak_storylines() +storys_2 = tool.peak_storylines() +defferent_list = tool.storylines_compare(storys, storys_2) + +app = QApplication(argv) +win = CompareWin() +win.load_differents(defferent_list, storys, storys_2) +win.show() +app.exec() \ No newline at end of file diff --git a/frame/CompareWindow.py b/frame/CompareWindow.py new file mode 100644 index 0000000..8b3f761 --- /dev/null +++ b/frame/CompareWindow.py @@ -0,0 +1,56 @@ +from PyQt5.QtWidgets import QWidget, QTreeView, QVBoxLayout +from PyQt5.QtGui import QStandardItemModel, QStandardItem +from typing import List +from parse.ast_load import StoryLine, FragmentSlice, items_map + + +class CompareWin(QWidget): + def __init__(self): + QWidget.__init__(self) + self.setWindowTitle("故事线比较") + + self.__compare_model = QStandardItemModel(self) + self.__compare_view = QTreeView(self) + self.__compare_model.setHorizontalHeaderLabels(["节点名称", "比对参数"]) + self.__compare_view.setModel(self.__compare_model) + + layout = QVBoxLayout(self) + layout.addWidget(self.__compare_view) + pass + + def load_differents(self, changed: List[str], base_list: List[StoryLine], other_list: List[StoryLine]): + base_map = items_map(base_list) + other_map = items_map(other_list) + + for changed_item in changed: + item = QStandardItem(changed_item) + item2 = QStandardItem() + item.setEditable(False) + item2.setEditable(False) + self.__compare_model.appendRow([item, item2]) + + if changed_item in other_map: + story_origin = other_map[changed_item] + item_o = QStandardItem(story_origin.signature) + if not changed_item in base_map: + item2.setText("append") + else: + item2.setText("modify") + item_o2 = QStandardItem(story_origin.file_path) + item_o.setEditable(False) + item_o2.setEditable(False) + item.appendRow([item_o, item_o2]) + pass + else: + if changed_item in base_map: + story_modif = base_map[changed_item] + item_ext = QStandardItem(story_modif.signature) + item2.setText("remove") + item_ext2 = QStandardItem(story_modif.file_path) + item_ext.setEditable(False) + item_ext2.setEditable(False) + item.appendRow([item_ext, item_ext2]) + pass + pass + pass + pass diff --git a/frame/__init__.py b/frame/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/frame/__pycache__/CompareWindow.cpython-312.pyc b/frame/__pycache__/CompareWindow.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f9329492579b4c72a4b24addf1e9ba065a344ab GIT binary patch literal 3047 zcmahLOKcm*b(UN%hvbr?tW9J|w53XRCEAv18;E1Yu>x3fY@@Pb)vDdHYPM_bNLq&E zD!VJ$bXGv&I)IS6D2>#RfL_>BS@>Wd;~df+0|W)MAd6)ODr}(sq&J~TFFAE)s3j#^ zi3Zr2x9`1q^WK~HnXjVJFd$>`#i!GMhXDMW{&*v>32eMifMuWpmCJxEm*TR%lrQT~ z`8kU7W%z6$703!Hf&Ke4!7NNc2J@LvHk=A)BdJJMOo<%ufpb6&+y<(ExcmN^{8Tg_ zOv3-rpQIlL$FFMY46<-&e8NEJiiWP^$oQ2r`i)T~ug_aaAKo*5*-~<aa@OUHHid9VBfCvGtISQ+6sgU@&7X~v z1XuSu*<-z)6zal-ac$_f0NDu8>GD(*}|l94GzoGo$z{C8_4uTHmryTZKDef zY?{Qt%Ol!HN{rZGvWspI=hTG-FEz9y$?Z)LS4M~H#9k=bs zut1}_jR-ui8`@1hXDONUNKuh7s$4@E6GK8`ac$5W$00>kYgs{}pEprv8Vebg4JM75 zuC8wfN8XyeWaw!$Wto$g^46@Ln`D7MJd372n9%i%IXP`8Sv1+umsm0|mp7<;ZniYg z1D?h7n#?<7`ZZXCO)lK)z`ZL{1@5mx(S;oj>{w0oSKz?Y&SMV`lsn&C;wvz*w!gQ; z|52xK2jfdPFyX=z4m|N$?915dn^!CFXLSKCJmA0s#R>P|pmT7r0^fStoLHGCH+L@y zRT%S*blZ+NZAU7wpX}Qp`T!i9npJW$NX4ORiizY5Np&37tyyF+c&Z-pgqeDf|pT&U9jer98%WI@Q3Ko^YhAq@Nf(`8bP3j`FgS+La4R_@L>3UXf z3MNZB)POz64%%>ACJJ_70T_4efX%AYVyK~`9ZIum@9nLvb!)=5VDk%{v4`jv-OfY* z)VjYokZb-9p1Suqu@u!lkqy0(@v)jIwk0S$WoPbTO6uoDh0*OM3!kU#ypz?bUuznlQwRd z6v!DZhXsn1bsVg%$BBZB%uK+LVVN2pbljwct!w)*_EJrnGP6u84zAnmShU zPE%jCv#*qJI!_eDwYDD?ZMXNd(|fwyHdGL*tv$sXPV0}VQrq&yyBCXn|Bwzp@!*Pd zc&)v+B)WY=PTx?u{hdOv8h_o5cRTU!;v1ECvKnu7<2_Eir+Bs!KU9rN%dxw$qEHI1 zb{?(7j}gR^md@fyr{!?9`%vj^r~72#$7`KOO22UX&p7>O%ALc7^YxSIX~|AiCb(6NnbA((s@1>wtitP5dqSNM_(_>it!D z)=6pKP(n=@l{1!%;igOZaqEqNaq<+PuT+!05?HIRwd#mRKR2(jCqgZq1S>zMlhKL<5Rx$u!z(n$yBu%Ri>_3HnRD!OZv;zFl*|ka3FO=#$XwA=A2_;C{*n2`SiA+)Yn literal 0 HcmV?d00001 diff --git a/frame/__pycache__/__init__.cpython-312.pyc b/frame/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9cabe467e0f5f0e6ac9379fe1f0b80e9c32604a1 GIT binary patch literal 149 zcmX@j%ge<81Qs_Zr-A6lAOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdW#VEL6Ht_&m6}{q z91~Dkl98Vm6I_yCROy_Nnw%YypPy44lU9_Nn;H`zpP83g5+AQuQ2C3)CO1E&G$+-r Wh!toEBM=vZ7$2D#85xV1fh+*PZX|F3 literal 0 HcmV?d00001 diff --git a/parse/__pycache__/__init__.cpython-312.pyc b/parse/__pycache__/__init__.cpython-312.pyc index fd33a098c62f6ef74408cf3e80d2d0e6806f3e44..08e7bfef388e8fc690fa039db4ec6b9a7855f28e 100644 GIT binary patch delta 32 mcmbQhIF*s>G%qg~0}#X=naE|rXfn}Wg4H=AH931?xFrC3ya+P@ delta 26 gcmbQrIDwJtG%qg~0}#Z`n8;@`kW}M1yZ5 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 J5zOh}{tIPq?STLQ literal 3391 zcmcH*O>YxNboR?$J8=?79O8W8B&5Mb#83!=v=pjBktjq+K`IJ~Rwla%PW_S2ELCjT zhyw>pye`edX)4fsF3p?qM_PWzOA*0R43ioLAo8U+GqZcnPtGzkO*4sj z${1gXF>~JLZo~Rhq;>$-Ys4Tkf=*^cT`;5tQ5WyZGqNsmTn1dpC=rhp_>9IDlSay% zPQ>R8%g5r2shD|-8uJb}XqAd34NbHB znwCuKw-SiAYT8$~Vu|{W#7s)t-~vVMo)CVSzfK`i2?uC$)(hY+sfv;kD2~(!OjWJ}P7(R<+XZY}y z8+sW+(IpYd4yFKlPGb-(@pOt=?F;qT)ffgZqb+cDr(3wWvYp$axlw{9Wc>iPqhw%z zL4L0GR`w6!++R^!xv4B~{k;Z_Fd2A4OacNCLzZA}9!q$lY2<{b^;8jvqn$`m63Y`? zUN%y?6Jvuw+o_DzY47u7a*U82+@ahq`yph40Q6K_H`Lye+Pk3+mDHi)*mL!LS4o9i z@c&eC0ED1n0FHjcfH&wDtjpi%)ol3B8aAFl&O3GNFRA?->PSf)DW2b<<5WbYU2v2J z5p*Nihk&Ql5Mn%y4j|Tp0F%?sFU%;40E3ae2LSU+w(|?7YAYnx`mq}3S5-y)^p0G^ ziw(KvghlNH?EHgVlMIjHMJGbWDUfk$#uM>c>L<*+g7wi-u|O`z%$p7Vli>mn(cAo$ z#-uYH8K9Qyg42BRVoqFA;CRz`T3_cS6DtfKOIT=|Mow~q8&cZkV|N6R-iUbU7~HVr zG{m_jQzNERl*5v)UA|;%5l=BQBHKllpXItO#1nNbu>dgCEDXbT4*D;<$1#SR;pj(p z3;;xaPZ$brV6$`IL$!FI+&NZIE1i97r&muuI8#tJdj=l+9{Gv~%RPtin41$GYCt1Q z&AY7)n4!4bs8<2`H+c_6uJh4FbY)&JT?1{`glQ;sQ`tZi9D4oeT=c9NPZ|`fAymM_ zFj>k9`k4oAJ&!D3%rvQnCmXUUuxO+V8Z!;PmF;#7)IdK3OxY*^uu@mg+U3>D8(m|i zuCev@a@WZp_msLmEciCt_ufDC&FyFE08fbqd!P>79!EgC|7MT8kQ2_4xv#+{7=FmD zY3QPBJBiy)+P0l8=cFv0cTVKxckoc$6G~2j_n-shJvn*F4e0Gha~|icK<)))@(zyf zsk}Gmt#ed!>R)S+_aVo7D>797h<7UMM_)%7{_S;Ws1$ntX@S^|C@ErsI_3E#0=>}_88EkAFq_+QB^87HgF zc|?nwMv_?yUt0l}j7%8*6=5#g!~Pj+Up8W2YMeV~nC)?cuW2U=x7l|9ApC-%wYk-~ zjo`sj@ZfrXIe4Pre;M4rMOu6lh4Yor;N!kWeZ?=zp~LI3Qs_wG;%4uG;qHN=M&DN3_%t{Xu@-F;VI0swzOQs$_8F@%2a7 z*Zax?6NRZtXl#oJfr Dict[str, 'StoryLine']: + map: Dict[str, 'StoryLine'] = {} + for inst in items: + map[inst.signature] = inst + pass + return map + + class FragmentSlice(): - def __init__(self, signature: str): + """ + 故事情节片段 + """ + def __init__(self, signature: str, file_path: str): self.signature = signature + self.file_path = file_path self.text_sections = [] + self.refer_items: 'FragmentSlice' = [] pass def append_text_section(self, section: str): + """ + 添加描述文本段落 + + :param section: 文本段落 + :return: None + """ self.text_sections.append(section) pass + def append_refer_slice(self, refer:'FragmentSlice'): + """ + 添加引用描述段落内容 -class StorySlice(): - def __init__(self, signature: str): + :param refer: 引用段落 + :return: None + """ + self.refer_items.append(refer) + pass + + def content_equal(self, other: 'FragmentSlice') -> bool: + """ + 内容比较 + + :param other: 其他片段 + :return: 比较结果 + """ + if self.signature != other.signature: + return False + + if len(self.text_sections) != len(other.text_sections): + return False + + for line0 in self.text_sections: + if not line0 in other.text_sections: + return False + pass + + if len(self.refer_items) != len(other.refer_items): + return False + + for slice in self.refer_items: + find: bool = False + for slice_1 in other.refer_items: + if slice.content_equal(slice_1): + find = True + pass + pass + + if not find: + return False + pass + + return True + + +class StoryLine(): + """ + 故事线结果 + """ + def __init__(self, signature: str, file_path: str): self.signature = signature + self.file_path = file_path self.text_sections = [] self.fragment_slices = [] pass def append_text_section(self, section: str): + """ + 添加文本描述 + + :param section: 文本段落 + :return: None + """ self.text_sections.append(section) pass def append_fragment_slice(self, slice: FragmentSlice): + """ + 添加情节 + + :param slice: 情节实例 + :return: None + """ self.fragment_slices.append(slice) pass + def content_equal(self, other: "StoryLine") -> bool: + """ + 内容比较 + + :param other: 其他实例 + :return: 比较结果 + """ + if self.signature != other.signature: + return False + + if len(self.text_sections) != len(other.text_sections): + return False + + for line in self.text_sections: + if not line in other.text_sections: + return False + pass + + if len(self.fragment_slices) != len(other.fragment_slices): + return False + + for slice0 in self.fragment_slices: + find: bool = False + for slice1 in other.fragment_slices: + if slice0.content_equal(slice1): + find = True + pass + pass + if not find: + return False + pass + + return True class AstParse(): + """ + Ast解析器 + """ def __init__(self, ast_path: str): self.ast_path = ast_path ast_file = open(ast_path, "rb") @@ -52,27 +168,42 @@ class AstParse(): pass def generate_time(self) -> str: + """ + 获取生成时间 + + :return: 生成时间字符串 + """ attr_time = self.ast_inst.xpath("/ast[1]/@time")[0] return str(attr_time) - def peak_storylines(self) -> List[StorySlice]: + def peak_storylines(self) -> List[StoryLine]: + """ + 提取所有故事线 + + :return: 故事线列表 + """ story_list = self.ast_inst.xpath("/ast/story") # 获取所有故事节点 story_items = [] + fragm_map: Dict[str, FragmentSlice] = {} for story in story_list: story_name = story.xpath("@name")[0] - story_slice = StorySlice("story:"+story_name) + story_file = story.xpath("@file-path")[0] + story_slice = StoryLine("story:" + story_name, story_file) story_items.append(story_slice) - story_text_lines = story.xpath("text-section/@text") # 获取所有描述 + story_text_lines = story.xpath("text-section/@text") #获取所有描述 for line in story_text_lines: story_slice.append_text_section(line) pass - fragment_items = story.xpath("fragment") # 获取所有情节定义 + fragment_items = story.xpath("fragment") #获取所有情节定义 for fragm in fragment_items: - fragment_name = fragm.xpath("@name") - fragm_slice = FragmentSlice("fragment:"+story_name+"#"+fragment_name) + fragment_name = fragm.xpath("@name")[0] + fragm_slice = FragmentSlice(f"fragment:{story_name}#{fragment_name}", story_file) + story_slice.append_fragment_slice(fragm_slice) + fragm_map[fragm_slice.signature] = fragm_slice + fragm_text_lines = fragm.xpath("text-section/@text") for line in fragm_text_lines: fragm_slice.append_text_section(line) @@ -80,14 +211,62 @@ class AstParse(): pass pass - fragm_refers = self.ast_inst.xpath("//refer") - for refer in fragm_refers: - story_name = refer.xpath("@story") - fragm_name = refer.xpath("@fragment") - story_refers = items_filter(story_items, lambda x:x.signature == f"story:{story_name}") - if(len(story_refers) > 0): - story_refer = story_refers[0] - + fragm_refer_items = self.ast_inst.xpath("//refer") + for refer_item in fragm_refer_items: + story_name_refer = refer_item.xpath("@story")[0] + fragm_name_refer = refer_item.xpath("@fragment")[0] + fragm_file = refer_item.xpath("@file-path")[0] + fragm_signature = f"fragment:{story_name_refer}#{fragm_name_refer}" + fragment_target = fragm_map[fragm_signature] + + fragm_pnode = refer_item.xpath("..")[0] + + if fragm_pnode.xpath("name()") == "story": + this_story_name = fragm_pnode.xpath("@name")[0] + refer_slice = FragmentSlice(f"refer:<{this_story_name}>{story_name_refer}#{fragm_name_refer}", fragm_file) + fragment_target.append_refer_slice(refer_slice) + + refer_lines = refer_item.xpath("text-section/@text") + for line in refer_lines: + refer_slice.append_text_section(line) + pass + pass + + if fragm_pnode.xpath("name()") == "article": + this_article_name = fragm_pnode.xpath("@name")[0] + this_volume_node = fragm_pnode.xpath("..")[0] + this_volume_name = this_volume_node.xpath("@name")[0] + refer_slice = FragmentSlice(f"refer-article<{this_volume_name}#{this_article_name}>{story_name_refer}#{fragm_name_refer}", fragm_file) + fragment_target.append_refer_slice(refer_slice) + + refer_lines = refer_item.xpath("text-section/@text") + for line in refer_lines: + refer_slice.append_text_section(line) + pass + pass + return story_items + def storylines_compare(self, base_list: List[StoryLine], other_list: List[StoryLine]) -> List[str]: + changed_list: List[str] = [] + base_map = items_map(base_list) + + for other_item in other_list: + if not other_item.signature in base_map: + changed_list.append(other_item.signature) + continue + + base_item = base_map[other_item.signature] + if not other_item.content_equal(base_item): + changed_list.append(other_item.signature) + pass + + base_map.pop(other_item.signature) + pass + + for addit in base_map.values(): + changed_list.append(addit.signature) + pass + + return changed_list