问题:
我想渲染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运行时作为依赖项添加到我的应用程序中,即使我想这样做,文档也是最糟糕的。
答案 0 :(得分:4)
2017年更新:
您可以使用ParseoidSharp获取完全兼容的MediaWiki渲染器
它通过NodeServices使用官方Wikipedia Parsoid库
(NetStandard 2.0)
由于Parsoid是GPL 2.0,而且GPL代码是通过网络在一个单独的进程中在nodejs中调用的,你甚至可以使用你喜欢的任何许可证;)
<小时/> 的预2017 强>
问题解决了。 正如最初假设的那样,解决方案在于使用C#中现有的替代解析器之一 WikiModel(Java)可以很好地实现这一目的。
首次尝试是pinvoke奇异果。 它有效,但失败了因为:
第二次尝试是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)
以下是我曾经实施解决方案的方法:
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 相同的事情,步骤也相当相似。
然后就这么简单
output = StaticNodeJSService.InvokeFromFileAsync(Of String)(HttpContext.Current.Request.PhysicalApplicationPath & "./NodeScripts/parsee.js", args:=New Object() {Markup})
奖励它现在比 ParseoidSharp 的方法更容易添加所需的选项,例如您可能希望将域设置为您自己的域。