为维基百科编辑差异和类型检测
项目描述
mwedittypes
为维基百科编辑差异和类型检测。目标是将维基百科文章的非结构化编辑转换为编辑中所采取动作的结构化摘要。该库有两种主要格式(和相关算法)
- 简单摘要:快速计算变更,生成基本变更计数摘要
- 结构化摘要:慢但更具有上下文感知的运算,提供每个特定变更的详细信息
安装
您可以使用pip
安装mwedittypes
$ pip install mwedittypes
示例
如果wikitext的一个修订版如下
{{Short description|Austrian painter}}
'''Karl Josef Aigen''' (8 October 1684 – 22 October 1762) was a landscape painter, born at Olomouc.
并且wikitext的第二个修订版如下
{{Short description|Austrian landscape painter}}
'''Karl Josef Aigen''' (8 October 1684 – 22 October 1762) was a landscape painter, born at [[Olomouc]].
发生的变更如下
- 将
landscape
添加到简短描述模板中--这将注册为模板变更。 - 将
Olomouc
更改为维基链接。 - 值得注意的是,尽管对模板进行了更改并添加了链接,但文章的“文本”没有改变。
此存储库将返回以下结构
- 简单:
{'Template':{'change':1}, 'Wikilink':{'insert':1}
- 结构化:
{'Template':[('parameter', {'1': 'Austrian painter'}, {'1': 'Austrian landscape painter'})], 'Wikilink':[('title', None, 'Olomouc')]}
基本用法
简单
>>> from mwedittypes import SimpleEditTypes
>>> prev_wikitext = '{{Short description|Austrian painter}}'
>>> curr_wikitext = '{{Short description|Austrian [[landscape painter]]}}'
>>> et = SimpleEditTypes(prev_wikitext, curr_wikitext, lang='en')
>>> et.get_diff()
{'Wikilink': {'insert': 1}, 'Template': {'change': 1}, 'Section': {'change': 1}}
结构化
>>> from mwedittypes import StructuredEditTypes
>>> prev_wikitext = '{{Short description|Austrian painter}}'
>>> curr_wikitext = '{{Short description|Austrian [[landscape painter]]}}'
>>> et = StructuredEditTypes(prev_wikitext, curr_wikitext, lang='en')
>>> et.get_diff()
{'context': [Context(type='Section', edittype='change', count=1)],
'node-edits': [NodeEdit(type='Wikilink', edittype='insert', section='0: Lede', name='landscape painter',
changes=[('title', None, 'landscape painter')]),
NodeEdit(type='Template', edittype='change', section='0: Lede', name='Short description',
changes=[('parameter', ('1', 'Austrian painter'), ('1', 'Austrian [[landscape painter]]'))])],
'text-edits': []}
在大多数情况下(约90%),两种方法在整体结果上是一致的。它们在以下情况下存在差异:
- 非常大的差异——当将
timeout
设置为True
时,StructuredEditTypes类更有可能回退到简单的差异并因此错过一些细节 - 内容移动——简化库无法检测到移动
- 更改与插入+删除——简化库无法区分例如,模板被更改与模板被删除并单独插入模板的情况
一个它们在输出中存在差异的差异示例是英语维基百科的第1107840666次修订(差异;模型输出)。
语言覆盖范围
这个库中的几乎所有内容都是语言无关的,因此可以一致地用于任何语言的维基百科。对于链接,命名空间识别各不相同,但我们使用一个涵盖所有语言的(在生成时)前缀列表。句子是半挑战性的,因为我们必须构建一个涵盖所有语言的句子结束标点符号列表。我们相信我们已经做得很好,但还没有明确测试这一点。该列表可以在mwedittypes/constants.py
中的SENTENCE_BREAKS_REGEX
下找到。单词是最具挑战性的方面,您将看到行为的变化。对于它们,我们采取了两种策略
- 对于大多数语言,我们根据空白分隔文本。这是默认行为。
- 有许多语言要么不使用空白分隔单词,要么使用空白来代替划分音节。这些可以在
mwedittypes/constants.py
中的NON_WHITESPACE_LANGUAGES
下找到。对于这些语言,我们则报告受影响的字符数。
已知问题
维基文本/语言非常复杂,因此有一些事情我们无法一致地提取。我们所知道的问题
- 句子:句号标点用于许多事情。缩写尤其具有挑战性,会导致句子被错误地分割。另一方面,泰语没有句子标点符号,因此每个段落(错误地)被视为一个单独的句子。
- 单词:我们尽最大努力提取空白分隔语言的单词,但一些语言使用特殊的间隔字符,这可能导致单词被错误地分割——例如,孟加拉语。我们已尽最大努力检测和考虑这些语言,但仍可能遗漏一些。
- 媒体:图像/音频/视频可以通过括号链接、模板和相册包含在文章中。它们都有自己的语法,特别是模板将图像名称与其格式化选项分开。对于相册/括号链接,我们将格式/标题选项与媒体关联,对其的更改将触发媒体更改。对于模板,我们无法这样做。
- 文本格式化:解析文本格式化非常复杂且依赖于上下文。我们按部分解析维基文本,因此可能在部分之间分割文本格式化可能会意外地解析。
对于链接,我们假设如果前缀不是用于媒体或类别,则链接是命名空间0的维基链接。这对于当前版本的维基百科文章通常是合理的,但对于用户页面链接或旧版本文章的跨语言链接,这可能会导致Wikilink
类过载。
开发
我们很高兴接受贡献,但将默认保持这里的代码相对通用(不是过度定制以适应个人用例)。请与我们联系或提出您希望合并的更改的问题,这样我们可以在之前进行讨论。
代码摘要——StructuredEditTypes
计算差异和运行编辑类型检测的代码可以在两个文件中找到
mwedittypes/tree_differ.py
:这是差异管道的第一阶段,用于检测高级更改。mwedittypes/node_differ.py
:这是diffing管道的第二阶段,它接收tree_differ的输出并收集每个变更的详细信息。
虽然diffing和计数并不简单,但这个过程最困难的部分是正确地将wikitext解析为节点(模板、 Wikilinks等)。这几乎全部是通过神奇的mwparserfromhell库实现的,在树differ中进行了一些调整。
- 我们使用链接命名空间前缀(例如,Category:、Image:)将类别和媒体从其他wikilinks中分离出来。
- 我们还识别了一些通过模板(例如,信息框)或画廊标签内嵌的额外媒体文件。
- 我们还添加了一些自定义逻辑来解析
<gallery>
标签以识别嵌套链接等,否则它们将被mwparserfromhell
视为文本。 - 我们使用自定义逻辑将wikitext转换为文本,以最好地匹配文章文本中出现的单词。
为了准确但高效地描述编辑中文本变化的规模,我们还使用了一些正则表达式和启发式方法来描述节点differ中一个编辑中更改了多少文本。这通常是diffing文本中最困难的部分,但由于我们不需要视觉上描述diff,只需估计变化的规模,我们可以使用相对简单的方法。为此,我们将文本更改分解为五个类别,并确定每个类别更改了多少:段落、句子、单词、标点符号和空白。
代码摘要 -- SimpleEditTypes
计算diffs和运行编辑类型检测的代码可以在一个文件mwedittypes/simple_differ.py
中找到。
库的大部分内容将wikitext文档解析为节点包(模板、 Wikilinks等)。这主要使用与StructuredEditTypes
相同的解析方法。
diffing组件简单地取每个wikitext文档相关的节点的对称差,以确定更改了什么,然后总结计数。
测试
组件的测试包含在tests
目录中。可以通过pytest运行。鉴于有众多的节点类型(模板、文本等)和四种操作(插入/删除/更改/移动),以及例如Text或类别/媒体节点所使用的不同语言,我们还没有达到全面的覆盖率,但我们正在努力扩大覆盖率。
发布
当准备发布时,有一些简单的步骤要遵循
- 根据语义版本控制更新
setup.py
和mwedittypes/__init__.py
中的版本号,并将其推送到Github。 - 使用相同的版本号创建一个标签(最容易在Github的下一步中完成)。
- 创建一个新的版本和更改摘要的Github发布。这将触发发布到PyPi的操作。
故障排除
- 如果出现问题,您总是可以回滚发布(在Github UI上)并删除相关的标签(在本地存储库上:
git tag -d [tag]; git push origin :[tag]
)并重试。 - 这依赖于PyPi秘密,因此您必须在Github存储库上具有正确的权限。
文档
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。