在C#中呈现MediaWiki的最佳方法

本文关键字:最佳 方法 MediaWiki | 更新日期: 2023-09-27 18:06:37

问题:

我想在C#中呈现MediaWiki语法(我指的是WikiPedia使用的MediaWiki语法,而不是来自其他引擎(如WikiPlex(的其他wiki格式(。

输入:MediaWiki标记字符串
输出:HTML字符串

有一些可供选择的mediawiki解析器,但在C#中没有,此外,由于这些库的结构,拼音C/C++看起来很惨淡。

作为语法指导,我使用http://en.wikipedia.org/wiki/Wikipedia:Cheatsheet

我的第一个目标是正确地呈现该页面的标记。

标记可以在这里看到:http://en.wikipedia.org/w/index.php?title=Wikipedia:Cheatsheet&action=编辑

现在,如果我使用Regex,它没有多大用处,因为不能准确地说出哪个标签结束于哪个起始标签,尤其是当一些元素(如italic(成为父元素的属性时。

另一方面,逐字符解析也不是一个好方法,因为例如"表示粗体,"表示斜体,"代表粗体和斜体。。。

我研究了移植其他一些解析器的代码,但java实现很模糊,Python实现有非常不同的regex语法。

到目前为止,我看到的最好的方法是将mwlib移植到IronPythonhttp://www.mediawiki.org/wiki/Alternative_parsers

但坦率地说,我并不期待将IronPython运行时作为应用程序的依赖项添加到我的应用程序中,即使我愿意,文档也充其量是糟糕的。

在C#中呈现MediaWiki的最佳方法

2017年更新:
您可以使用ParseoidSharp来获得完全兼容的MediaWiki渲染器
它通过NodeServices使用官方的维基百科Parsoid库
(NetStandard 2.0(由于Parsoid是GPL2.0,并且GPL代码是在nodejs中通过网络在单独的过程中调用的,因此您甚至可以使用任何您喜欢的许可证;(


2017年前

问题解决了。正如最初假设的那样,解决方案在于使用C#中现有的替代解析器之一
WikiModel(Java(可以很好地实现这一目的。

第一次尝试是pinvokekiwi。它起了作用,但失败了,因为:

  • kiwi使用char*(在任何非英语/ASCII上都失败(
  • 线程不安全
  • 糟糕是因为需要在每个体系结构的代码中都有一个本机dll(确实添加了x86和amd64,然后它在我的ARM处理器上爆炸了(

第二次尝试是mwlib。这失败了,因为不知何故,IronPython并没有正常工作。

第三次尝试是Swebele,它本质上是学术性的vapoware。

第四次尝试是使用最初的mediawiki呈现器,使用Phalanger。这失败了,因为MediaWiki呈现器并不是真正的模块化。

第五次尝试是通过Phalanger使用Wiky.php,这很有效,但速度很慢,而且Wiky.php并没有完全实现MediaWiki。

第六次尝试是通过ikvmc使用bliki,但由于过度使用了它编译的第三方库===>而失败,但只产生了空引用异常

第七次尝试是在C#中使用JavaScript,虽然有效,但速度非常慢,而且实现的MediaWiki功能非常不完整。

第8次尝试是通过Regex编写自己的"解析器">
但让它发挥作用所需的时间太长了,所以我停了下来。

第9次尝试成功。在WikiModel上使用ikvmc会产生一个有用的dll。问题是示例代码已经过时了。但使用谷歌和WikiModel源代码,我能够将其拼凑在一起。

最终结果可在此处找到:
https://github.com/ststeiger/MultiWikiParser

为什么正则表达式不能实现这一点?

inputString = Regex.Replace(inputString, @"(?:'''''')(.*?)(?:'''''')", @"<strong><em>$1</em></strong>");
inputString = Regex.Replace(inputString, @"(?:''')(.*?)(?:''')", @"<strong>$1</strong>");
inputString = Regex.Replace(inputString, @"(?:'')(.*?)(?:'')", @"<em>$1</em>");

据我所见,这将呈现所有"粗体和斜体"、"粗体"answers"斜体"文本。

以下是我曾经如何实现一个解决方案:

  • 为Markup->HTML转换定义正则表达式
  • 正则表达式必须是非贪婪的
  • 收集Dictionary<char, List<RegEx>>中的正则表达式

char是每个RegEx中的第一个(Markup(字符,RegEx必须按Markup关键字长度desc排序,例如=====之前。

遍历输入字符串的字符,并检查Dictionary.ContainsKey(char(。如果是,请在列表中搜索匹配的RegEx。第一个匹配的RegEx获胜。

由于MediaWiki允许递归标记(<pre>和其他标记除外(,标记中的字符串也必须以这种方式递归处理。

如果匹配,则跳过输入字符串中与RegEx匹配的字符数。否则继续下一个字符。

Kiwi(https://github.com/aboutus/kiwi,上提到http://mediawiki.org/wiki/Alternative_parsers)可能是一个解决方案。由于它是基于C的,I/O只是由stdin/stdout完成的,因此从中创建一个"PInvoke"功能DLL应该不会太难。

与公认的解决方案一样,我发现parsoid是最好的前进方式,因为它是官方库,并且对维基媒体标记有最大的支持;也就是说,我发现ParseoidSharp使用了过时的方法,如Microsoft.AspNetCore.NodeServices,实际上它只是一个相当旧版本的pasoid的npm包的包装器。

由于node.js中有一个相当新的parsoid版本,您可以使用Jering.Javascript.NodeJS来做与ParseoidSharp相同的事情,因此步骤也相当相似。

  1. 安装nodeJS(
  2. 下载parsoidhttps://www.npmjs.com/package/parsoid在项目中放置所需的文件
  3. 在您的项目的powershell cd中
  4. npm安装

那么它就像一样简单

output = StaticNodeJSService.InvokeFromFileAsync(Of String)(HttpContext.Current.Request.PhysicalApplicationPath & "./NodeScripts/parsee.js", args:=New Object() {Markup})

另外,它现在比ParseoidSharp的方法更容易添加所需的选项,例如,您可能想将域设置为自己的域。