在C#中渲染MediaWiki的最佳方法?

时间:2011-08-23 11:04:25

标签: c# asp.net parsing .net-core mediawiki

问题:

我想渲染MediaWiki语法(我指的是WikiPedia使用的MediaWiki语法,而不是其他一些引擎,如WikiPlex的其他wiki格式),以及C#中的语法。

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

有一些替代的mediawiki解析器,但C#中没有任何内容,而且由于这些库的结构,另外对C / C ++进行编程看起来很惨淡。

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

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

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

现在,如果我使用正则表达式,它没有多大用处,因为我不能确切地说哪个标记结束了哪个标记,特别是当某些元素(如斜体)成为父元素的属性时。

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

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

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

但坦率地说,我并不期待将IronPython运行时作为依赖项添加到我的应用程序中,即使我想这样做,文档也是最糟糕的。

5 个答案:

答案 0 :(得分:4)

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

<小时/> 的预2017

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

首次尝试是pinvoke奇异果。 它有效,但失败了因为:

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

第二次尝试是mwlib。 那失败了,因为不知何故IronPython不能正常工作。

第三次尝试是Swebele,基本上是学术上的vapoware。

第四次尝试是使用Phalanger使用原始的mediawiki渲染器。之所以失败,是因为MediaWiki渲染器并非真正模块化。

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

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

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

第8次尝试是通过Regex编写自己的“解析器”。
但是让它工作所需的时间过长,所以我停了下来。

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

最终结果可以在这里找到:
https://github.com/ststeiger/MultiWikiParser

答案 1 :(得分:2)

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

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

据我所知,这将呈现所有“粗体和斜体”,“粗体”和“斜体”文字。

答案 2 :(得分:2)

以下是我曾经实施解决方案的方法:

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

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

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

由于MediaWiki允许递归标记(&lt; pre&gt;和其他)除外,标记内的字符串也必须以递归的方式处理。

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

与公认的解决方案一样,我发现 parsoid 是最好的前进方式,因为它是官方库 - 并且对维基媒体标记有最大的支持;也就是说,我发现 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 安装

然后就这么简单

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

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