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

Posted

技术标签:

【中文标题】在 C# 中呈现 MediaWiki 的最佳方法?【英文标题】:Best approach to render MediaWiki in C#? 【发布时间】:2011-11-01 20:49:41 【问题描述】:

问题:

我想渲染 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 实现有非常不同的正则表达式语法。

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

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

【问题讨论】:

看看 WikiPlex 是如何做到的。那时你所要做的就是修改它。 @Ramhound:好主意。我认为他们使用正则表达式,AFAIK。不确定这是否适用于 MediaWiki,因为它有点复杂。此外,它们将所有内容呈现为 HTML 标签,因此没有 css,也没有属性,但有很多不推荐使用的标签,例如 . “猕猴桃”呢? (github.com/aboutus/kiwi,在mediawiki.org/wiki/Alternative_parsers 上提到)。由于它是基于 C 的,并且 I/O 只是由 stdin/stdout 完成,因此从它创建一个“PInvoke”-able DLL 应该不会太难。 @Doc Brown:在尝试编译时,我得到:leg -o src/syntax.leg "make: leg: command not found" @Quandary:leg 是一个解析器生成器 (piumarta.com/software/peg),不知道这东西的便携性如何。也许您应该联系 kiwi 的作者,询问他们是否可以使用 MSVC 编译该东西。我没有发表我的评论作为答案,因为我没有自己尝试过,也不知道这种方法是否值得努力。 【参考方案1】:

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


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,由于过度使用 3rd 方库而失败 ==> 它编译,但仅产生空引用异常

第七次尝试是在 C# 中使用 javascript,它可以工作但速度很慢,而且实现的 MediaWiki 功能非常不完整。

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

第 9 次尝试成功。 在 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>");

据我所知,这将渲染所有“粗体和斜体”、“粗体”和“斜体”文本。

【讨论】:

因为有嵌套列表(带枚举)和表格之类的东西。【参考方案3】:

这是我曾经实施解决方案的方式:

为标记定义正则表达式->HTML 转换 正则表达式必须是非贪婪的 收集Dictionary&lt;char, List&lt;RegEx&gt;&gt;中的正则表达式

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

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

由于 MediaWiki 允许递归标记(

 和其他标记除外),标记内的字符串也必须以这种方式递归处理。

如果有匹配,则向前跳过与输入字符串中的正则表达式匹配的字符数。否则继续下一个字符。

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

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

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

    安装 nodeJS ( 下载 parsoid https://www.npmjs.com/package/parsoid 将所需文件放入您的项目中。 在您的项目中使用 powershell cd npm 安装

那么就这么简单

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

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

【讨论】:

以上是关于在 C# 中呈现 MediaWiki 的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章

在 jquery datatables.net 中呈现布尔数据列的最佳方法

检查UIAlertController是否已经呈现的最佳方法是什么?

c# 在 c# 应用程序中保存配置数据的最佳方法是啥。 [复制]

从数据库呈现erb的最佳方法?

在 SpriteKit 中呈现图像的最佳方式

在 C# 中处理整数溢出的最佳方法?