在C#中呈现MediaWiki的最佳方法是什么?

7
问题:
我想呈现MediaWiki语法(我的意思是由WikiPedia使用的MediaWiki语法,而不是来自其他引擎(如WikiPlex)的其他维基格式),并且要用C#实现。
输入:MediaWiki标记字符串 输出:HTML字符串
有一些替代的mediawiki解析器,但没有C#版本。此外,由于这些库的结构,pinvoke C / C ++看起来很困难。
作为语法指南,我使用http://en.wikipedia.org/wiki/Wikipedia:Cheatsheet 我的第一个目标是正确呈现该页面的标记。
可以在此处查看Markup: http://en.wikipedia.org/w/index.php?title=Wikipedia:Cheatsheet&action=edit 现在,如果我使用Regex,它就没什么用了,因为不能确切地说哪个标记结束哪个开始,特别是当一些元素(例如斜体)成为父元素的属性时。
另一方面,逐个字符解析也不是一个好的方法,因为例如'''表示粗体,''表示斜体,而'''''表示粗体和斜体...。
我研究了一些其他解析器代码的移植,但Java实现是晦涩的,Python实现的正则表达式语法非常不同。
到目前为止,我看到的最好的方法是将mwlib移植到IronPython上http://www.mediawiki.org/wiki/Alternative_parsers
但坦白地说,我并不希望将IronPython运行时添加为我的应用程序依赖项,即使我想要这样做,文档也很糟糕。

2
看看WikiPlex是如何做的。在那时,你所要做的就是修改它。 - Security Hound
@Ramhound: 好主意。我想他们使用正则表达式,据我所知。不确定对于MediaWiki是否适用,因为它更加复杂一些。此外,他们渲染所有内容为HTML标记,因此没有css和属性,但有很多已弃用的标记,例如<b>或<i>。 - Stefan Steiger
3
“Kiwi”是什么?(https://github.com/aboutus/kiwi,在http://www.mediawiki.org/wiki/Alternative_parsers上提到)。它基于C语言,输入和输出使用stdin/stdout完成,因此很容易从中创建一个“PInvoke”的DLL。 - Doc Brown
@Doc Brown:尝试编译时,我收到以下错误信息:leg -o src/syntax.leg "make: leg: command not found" - Stefan Steiger
2
@Quandary:leg是一个解析器生成器(http://piumarta.com/software/peg/),不知道这个东西有多可移植。也许你应该联系kiwi的作者,问问他们这个东西是否可以用MSVC编译。我没有将我的评论发布为答案,因为我自己没有尝试过,也不知道这种方法是否值得一试。 - Doc Brown
显示剩余5条评论
5个回答

4
2017更新:
您可以使用ParseoidSharp来获取完全兼容的MediaWiki渲染器。
它通过NodeServices使用官方的WikipediaParsoid库。
(NetStandard 2.0) 由于Parsoid是GPL 2.0,而且在单独的进程中通过网络调用GPL代码,因此您甚至可以使用任何许可证;)

2017年之前:
问题已解决。 正如最初的假设,解决方法在于使用C#中现有的替代解析器之一。
WikiModel(Java)很适合这个目的。

第一次尝试是pinvoke kiwi。它确实起作用,但失败了,因为:
  • kiwi使用char*(对于任何非英语/ ASCII都会失败)
  • 不是线程安全的。
  • 需要在代码中为每个体系结构添加本机dll,因为这很糟糕(添加了x86和amd64,然后在我的ARM处理器上就挂了)
第二次尝试是mwlib。由于IronPython不起作用,所以失败了。
第三次尝试是Swebele,它实际上被证明是学术vapoware。
第四次尝试使用原始的mediawiki渲染器,使用Phalanger。由于MediaWiki渲染器实际上不是模块化的,因此失败了。
第五次尝试是通过Phalanger使用Wiky.php,这起作用了,但速度很慢,并且Wiky.php没有完全实现MediaWiki。
第六次尝试是通过ikvmc使用bliki,由于过多地使用第三方库而失败==>它编译了,但仅产生null引用异常。
第七次尝试是在C#中使用JavaScript,这起作用了,但速度非常慢,而且实现的MediaWiki功能非常不完整。
第八次尝试是通过Regex编写自己的“解析器”。但是使其工作所需的时间太长了,所以我停止了。
第九次尝试成功了。在WikiModel上使用ikvmc可以生成有用的dll。问题在于示例代码已经过时了。但是使用Google和WikiModel源代码,我能够把它拼凑在一起。
最终结果可以在此处找到:
https://github.com/ststeiger/MultiWikiParser

2
为什么我们不能用正则表达式来实现这个功能呢?
inputString = Regex.Replace(inputString, @"(?:'''''')(.*?)(?:'''''')", @"<strong><em>$1</em></strong>");
inputString = Regex.Replace(inputString, @"(?:''')(.*?)(?:''')", @"<strong>$1</strong>");
inputString = Regex.Replace(inputString, @"(?:'')(.*?)(?:'')", @"<em>$1</em>");

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


因为有嵌套列表(带枚举)和表格这样的东西。 - Stefan Steiger

2
这是我曾经实现的一个解决方案:
  • 定义用于标记->HTML转换的正则表达式
  • 正则表达式必须是非贪婪的
  • 将正则表达式收集到一个Dictionary<char,List<RegEx>>

字符是每个RegEx中第一个(标记)字符,RegEx必须按标记关键字长度降序排序,例如 === == 之前。

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

由于MediaWiki允许递归标记(除了

和其他标记),因此还必须以这种方式递归地处理标记内部的字符串。

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


0

就我的经验而言,我发现Parsoid是前进的最佳方式,因为它是官方库,并且对Wikimedia标记具有最大的支持;尽管如此,我发现ParseoidSharp使用的方法已过时,例如Microsoft.AspNetCore.NodeServices,实际上它只是pasoid的npm包的一个相当旧的版本的包装器。

由于node.js中有一个相当当前的parsoid版本,您可以使用Jering.Javascript.NodeJS来执行与ParseoidSharp相同的操作,步骤也相当类似。

  1. 安装nodeJS(
  2. 下载parsoid https://www.npmjs.com/package/parsoid将所需文件放入您的项目中。
  3. 在powershell中cd到你的项目下
  4. npm install

然后它就像这样简单

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

奖励是现在比ParseoidSharp的方法更容易添加所需的选项,例如,您可能希望将域设置为自己的域。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接