在 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<char, List<RegEx>>
中的正则表达式
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是否已经呈现的最佳方法是什么?