View source for WackoWiki Markup

其他语言 ((/Doc/Deutsch/Markup Deutsch)), ((/Doc/Español/Markup Español)) and ((/Doc/Русский/Разметка Русский)).

这篇比较长的文章介绍了“Wacko 标记”是如何出现的,以及为什么它现在是这个样子的。如果你不知道什么是“Wacko 标记”,尤其是不清楚什么是“wiki”,你应该先到 WackoWiki 项目站点阅读几篇 ((/Doc/English documentation)) 的文章,特别是关于 ((/Doc/English/WikiConcept wiki-concept)) 的那篇文章。

{{toc numerate=1}}

===关于 Wacko 标记 ===
简而言之,Wacko 标记是一种特殊的文本格式化方式,它只需最少的特殊字符并尽量不破坏“源文本”的可读性,就能在程序转换后得到漂亮的 HTML。

Wacko 标记的功能足以对大大小小的页面进行完整的排版。除了传统的“斜体”“粗体”“下划线”和“删除线”等修饰外,还有列表(包括多级列表)、标题、表格、图片、引用高亮等多种标记方式。

Wacko 标记用于 WackoWiki 引擎以及其他开发者的项目中。若要将 Wacko 标记嵌入你的项目,只需下载并集成以下组件:
  * ((/Dev/Projects/WackoFormatter Wacko 格式化器)),一个将 Wacko 标记转换为 HTML 的 PHP 类;
  * ((/Dev/Projects/WikiEdit 可视化编辑器)),用于 wiki 的编辑器。该项为可选,但与 Wacko 格式化器结合使用非常方便。

本文的源文本采用 Wacko 标记格式撰写,((!/source 可供查看))。

===基本原则 ===
尽管(我们是 WackoWiki 的作者、开发者)最初从 ((/Doc/English/WakkaWiki WakkaWiki)) 项目继承了 Wacko 标记(该项目此前位于 ~http://wakkawiki.de,现在已不可用),但我们是基于一组清晰的原则对其进行了发展,这些原则决定了它日后的成功。

因此,标记规则的形成虽然是“进化式”的,但始终由少量原则引导,使得标记保持便捷与自然。

这些原则旨在实现以下目标:
  * 降低“意外触发”的概率(即普通文本被误识别为标记);
  * 实现直观且易于记忆的标记;
  * 保护被格式化文本的环境,减少作者误输入造成的问题。

====语义应通过语法表达 ====
任何 wiki 标记都基于“所想即所得”(WYTIWYG)的原则,因此每条 Wacko 标记规则都试图用自身的语法反映语义。由于整个排版是通过可在键盘上输入的简单文本符号完成的,我们尝试找到能够反映含义的组合:
  * ##""**bold**""## —— 用星号表示粗体,显得与周围文本“分离”;
  * ##""//italics//""## —— 斜体由 // 这种“编织线”表示;
  * ##""--strikethrough--""## 与 ##""__underlining__""## 分别表示删除线和下划线;
  * 列表的书写方式与我们在文本输入域中习惯写列表时很相似。
在这里,我们有意不同于 ((http://c2.com/cgi/wiki?TextFormattingExamples) 经典) 的那种“每侧仅用 5 个撇号”式的 wiki 标记。

====成对字符 ====
如你所见,上述所有实例都包含成对出现的字符。得益于这一原则,从其他编辑器“直接粘贴”的文本通常不需要特殊预处理——这样的文本很少会恰好包含成对字符。

某些情形下会使用三连、四连乃至五六连字符来表示不同级别的标题。字符越多,标题层级越深。

====标记与内部文本接触 ====
你可能是那种在键入破折号时总用“两个减号”写法(像这样:##-~-##)的人。无论如何,作者显然也属于这一类。而大量文本中既作为破折号又作为其他用途出现的双减号并不少见。

“标记应与内部文本接触”的原则可避免将“普通文本”误转换为标记。并非所有标记规则都采用了这一原则,但对那些单个成对字符在“源代码”中有可能出现的标记(例如删除线)尤其重要。

例如:##""--which is how it works--""## 会产生删除线,而如果写成 ## ""--"" we do so--## —— 文本就不会被识别为删除线。

需要指出的是,本规则与前后规则的目标均是尽量减少标记处理的“意外触发”,即避免文本中的某些字符被误认为是标记的一部分。

====换行表示文本片段结束 ====
与 OpenWiki 标记不同,Wacko 标记中“源代码”的换行被字面理解为换行(两个换行表示新段落)。因此,我们将换行视为某个完结文本片段(如一句话或一段)的结束。

一些 Wacko 标记规则(如改变字体样式的规则:粗体、斜体、下划线等,以及标题)大多数仅作用于被换行限制的文本片段。采用该原则可以同时解决三类问题:
  * 降低“意外触发”的概率;
  * 简化对标记的理解(因为选区的“开始”和“结束”相距不远);
  * 降低“字体样式”在长文本中的作用,使其主要用于小范围文本格式化——这有助于提升最终效果的可读性。

====“损坏”的标记不应破坏周围的 HTML ====
上述原则使我们能解决一个很重要的问题——“保护”格式化文本周围的 HTML 不被可能的格式错误破坏。凭借“粘性”规则,我们几乎总能判定标记的“开始”和“结束”位置,从而一次性插入两个 HTML 标签(或根本不插入)。对于那些不易成对的 Wacko 标记规则,应尽力保证最终结果的“紧凑性”。事实证明,我们做到了这一点。

====必须能准确写出我想写的内容 ====
任何标记都应能“转义”,即让标记规则被忽略、文本片段原样通过格式化。这篇文章就是需要这种“转义”的典型例子。

====尽量减少键盘布局切换 ====
最后但同样重要的是,对于讲俄语的用户来说,这一原则在便利性上尤其关键(对英语用户也要兼顾)。

原则要点是选择那些大多数(尤其是高频)规则可以在俄语输入布局下直接输入的字符组合,同时也要考虑对英语读者的可访问性。

因此,原始的引用语法 ##""[[WikiLink Textual description]]""## 找到了对应的替代写法 ##""((WikiLink Text on link))""##,可在英文和俄文输入布局下使用。许多 wiki 标记规则都具备这一有益特性。

===标记规则 ===
在应用这些原则后,我们开发并改进了原有规则集,仔细研究了不同的 wiki 引擎。如果敢自夸,我会说最终的 wiki 标记融合了各类优秀规则,同时保持精简与简单。实际上,经过我们的努力,标记确实吸收了众多优秀规则,仍保持简洁。

本章简要说明我们如何确立若干关键标记规则。

====单行标记 ====
单行标记指那些使用在“普通文本”中常见符号、并用于文本局部排版的规则:
  * **粗体**、//斜体//、__下划线__
  * ++小号++ 和 ##等宽## 文本
  * 标题(与换行分割相关)
  * 链接(其文本通常也应保持“简短”)
  * ^^度数^^ 和 ,,上标/下标,,(仅在单词内有效)

====多行标记 ====
其余标记规则作用于较长的文本片段,通常因为它们的语义和表现形式应用于大段文本。

<[It's, like, a --strikethrough.
Or-- a quote that captures the entire paragraph.]>

====标记取消 ====
标记取消有两种实现方式:
  * 用“成对字符”进行块级取消 ##~""##;
  * 用转义符(在被取消序列前输入特殊字符)即波浪号 ##~~##。
第一种方法便于对大段文本禁用标记,第二种方法在你只想禁用一两个词或一个成对字符时更方便。此外,波浪号转义还能用于显示双引号,如上文示例所示。

如果你打开本篇文章的 ((!/source)),会发现标记取消非常常见——否则我们就无法展示未经处理的标记示例了。

====引用与图片 ====
Wacko 标记会自动将文本中的 URL 转为超链接。如果可以明显判断某 URL 是图片(例如以 .jpg 或 .gif 结尾)——则使用 <img> 标签将图片插入到格式化后的文本中。这很方便,允许你直接从剪贴板插入链接并获得不错的结果。

对于带说明的链接有两种常见写法:
  * ##""((URL 说明文本))""##
  * ##""[[URL 说明文本]]""## —— 功能相同,但不够方便
  * ##""((Wiki Reference With Spaces == 说明文本))""## —— 允许在 wiki 链接的“左侧”包含空格(方括号写法也支持此功能)

((/Doc/English/WikiName Wiki Link Concept)) 使得插入站内链接更为简便,Wacko 标记也考虑到了这一点。所有非“站内”链接会被立即识别为“外部”链接,电子邮件地址亦同。

图片说明的写法与链接说明类似:
  * ##""((picture.jpg 说明))""## 用于设置图片标题
  * ##""((URL small_picture.jpg))""## 用于将图片作为链接插入

====列表结构 ====
人们最自然地如何书写无序、有序以及嵌套列表?
#||
||%%(php)**可能像这样:**
  * 列表项-1
  * 列表项-2
  * 子列表
    * 子列表项-1
    * 子列表项-2
  * 列表继续
  
  1. 有序列表第一项
  2. 第二项
    1. 嵌套列表项
    6. 编号可能不连续
%%|

**你期望得到:**
  * 列表项-1
  * 列表项-2
  * 子列表
    * 子列表项-1
    * 子列表项-2
  * 列表继续
  
  1. 有序列表第一项
  2. 第二项
    1. 嵌套列表项
    6. 编号可能不连续
|| ||#
这就是 Wacko 标记中列表规则的组织方式。该示例很好地说明了为什么列表项的起始处要向右缩进两个字符——这样可以避免与 **粗体** 文本混淆。

缩进选择为两个字符,基于“成对字符”原则,这种字符在普通文本中几乎不会出现。其他一些 wiki 格式使用五到六个空格——你可以想象在 <textarea> 中第三级嵌套会是什么样子!

c2.com 的原始做法使用制表符,但我们认为这不合理:在大多数界面中 Tab 用于导航,有些浏览器根本无法在输入域中输入制表符。

有序列表的编号会自动生成,这使得删除项目、添加新项或改变层级变得容易。如果需要一个从数字三开始的有序列表,可以这样写:##1.#3 Like this##。
  1.#3 Like this.

====表格标记 ====
表格是任何标记中最难处理的部分之一。最好的方案是一组模拟表格竖线网格的规则。这样比用连字符、加号和竖线绘制整个网格要简单,而且源代码仍然可读。关于表格标记的更多信息请参见 ((/Doc/English/Formatting Wacko markup syntax)),其中有示例。

遗憾的是,表格标记是 Wacko 标记中最“脆弱”的部分,在某些情况下可能破坏页面外部环境的结构。这是我们为语法清晰和解析速度所愿意付出的代价。

===标记的发展 ===
首先,上文并未描述所有标记规则,仅列出最重要的。如有遗漏,请先查阅文档 ((/Doc/English/Formatting) 以获取更完整的说明)。如果现有规则不足以满足需求,则应扩展标记。大多数我们新增的规则正是如此产生的。

====何时应更改现有标记? ====
永远不要。

这里指的是在不引入新规则的前提下修改已有规则。更改已有标记的行为可能会严重打扰已经习惯该标记的人们。试想如果某些站点上 ##""<b>""## 被当作 ##""<a>""## 使用,反之亦然,那将多混乱。

当然,如果某个项目内的某条规则确实极大地妨碍了你的工作,你可以考虑替换它。但在替换/移除规则时,要考虑熟悉标准标记的所有用户将如何接受这些变动!

====何时值得引入新的标记实体? ====
尽量少引入。

Wacko 标记有“高亮器(highlighters)”的概念,它们是可插件式的实体,可以很容易地添加而不占用“主标记空间”——即成对字符。下文将描述高亮器的概念。

若未经充分考虑就新增成对字符,会让用户不得不重新记忆这些变化。正因为开发者对每条新规则的后果深思熟虑,用户才能无障碍地使用 Wacko 标记。

若你想扩展标记,最好联系该格式的作者——他们可能已有想法,或愿意采纳你的建议。协调一致的行动总是更有效。

===复杂转换与服务功能 ===
Wacko 标记的设计思想(源自 WakkaWiki 并由作者扩展)提供了两种方式,可以显著增强标记能力并在页面中嵌入复杂功能。

这两种方式是我们主要推荐给希望扩展标记规则的开发者的方式。此外,使用这些方法不需要深入解析 Wacko 格式化器的内部实现。

====高亮器的概念 ====
“高亮器”是一个允许开发者实现复杂文本块转换逻辑的概念,并让用户方便地将该文本块以特定格式呈现的机制。

在 Wacko 标记正文中,高亮器的使用形式如 ##""%%(html)<div class="test">testdiv</div>...%%""## —— 即使用成对字符 ##""%%""##,并在括号中指明将要对高亮块内容调用哪个高亮函数。

开发者编写这些函数,函数接收一个文本变量,对其进行某些转换,然后返回结果。

通常此语法用于各种文本“着色”——用于语法高亮、聊天记录或电子邮件的标记、插入某些特殊文本块等。

该概念既是扩展标记的简单方式,也是:
  * 无需使用额外“成对字符”的方式;
  * 无需了解格式化器细节的方式。

====Actions(动作)的概念 ====
“动作”是一个允许开发者实现复杂功能(可能需要与用户交互),并允许用户在页面中合适位置便捷调用该功能的概念。

在 Wacko 标记正文中,“动作”写法如 ##""{{changes page="/Dev"}}""## —— 使用成对字符 ##""{{""##,随后指定动作名及附加参数。

开发者以与编写高亮器相同的方式编写这些函数。

在 WackoWiki 中,借助“动作”实现了大量与页面交互的功能(构建目录、列出最近更改/评论、搜索等)。

该概念允许在页面中“嵌入”复杂功能,而无需深入了解 Wacko 格式化器的实现细节。

====Interwiki — 链接标记的扩展====
还可以通过添加类似 ##""((repository:address))""## 或 ##""((repository:address 链接文本))""## 的规则来扩展链接语法。在此类写法中,地址由两部分组成:“存储”与“该存储中的名称”。例如,指向 ((http://livejournal.com LiveJournal)) 的地址可写为 ##""((lj:mendokusee))""##,若要指向英文单词的翻译,可写 ##""((lingvo:fascinating))""##。

此概念(以及我们许多标记)继承自 wiki,最初用于指向其他 wiki 节点。我们发现它对其他用途也很有用。

当然,还有其它实现类似功能的方法。不同站点采用过下列标记格式:
  * ##""[[ljuser romochka]]""##(来源:[[http://ilyabirman.ru/meanwhile/wikihelp]])
  * ##""[[xpointUser280 Vladimir Palant]]""##(来源:[[http://xpoint.ru/help/formatting.xhtml]])
  * ##""[[php ereg_replace]]""##(来源:[[http://xpoint.ru/help/formatting.xhtml]])

带冒号的 interwiki 变体(repository:address)在许多系统中被使用,已成事实上的标准,因此我们认为它更为正确。此外,interwiki 不会与常见的 ##""[[Link Description]]""## 产生冲突。

===技术细节 ===
本文不是详细介绍 ((/Dev/Projects/WackoFormatter Wacko 格式化器)) 工作原理的场所,但有几点主要内容值得提及。

首先,格式化器本身基于正则表达式(即兼容 Perl 的正则表达式)并采用“递归解析”原则。也就是说,它尝试将文本分解为“最大”的标记片段,然后对这些片段内部再次进行解析。这也意味着你不能嵌套使用相同的标记规则:例如,像这样 ##""**example **nested** markup**""## 的写法无法工作。但你也会同意,这种嵌套通常并非必要。

其次,格式化器为更好地防止“意外触发”而分多轮处理。第一轮是一组简化规则,用于“转义”文本片段,禁止对其进行标记。在同一轮中,所有“高亮器”会被识别并保护,从而防止高亮器与其他标记相互重叠。第二轮则处理其余规则。

第三,格式化器支持对格式化结果进行缓存。由于某些标记需与用户交互或链接到页面(不同用户可能有不同处理方式),因此缓存时会生成一个只包含链接与“动作”等相关规则的“半成品”结果。最后一轮格式化是最快的一次,不需要递归,在显示页面内容时基于该“半成品”完成链接标记和插入“动作”。

若你对格式化更深层次的细节感兴趣,欢迎查阅 ((/Dev/Projects/WackoFormatter 代码格式))。

===注意事项 ===
本文旨在说明 Wacko 标记规则为何以及如何被发明,为什么会采用“成对字符”,并希望使用 Wacko 标记编辑格式的新项目能遵循其背后的原则。

如有疑问,欢迎在评论中提出或直接联系本文作者。

此致敬意,((/Org/Team WackoWiki 团队)) 及本文作者敬上。
  * ((user:KusoMendokusee KusoMendokusee))
  * ((user:RomanIvanov RomanIvanov))

===参考资料===
1. ((https://wackowiki.org WackoWiki 项目))
2. ((/Dev/Projects/WackoFormatter Formatter)) 有关所述标记的说明
3. ((/Dev/Projects/WikiEdit Visual Editor)) 有关所述标记的说明
2. ((https://web.archive.org/web/20050211022800/http://www.wakkawiki.de/WakkaWiki WakkaWiki)) —— WackoWiki 的历史渊源
3. ((https://web.archive.org/web/20060202001402/http://openwiki.com/ OpenWiki)) —— Wacko 标记语法的另一个历史渊源
4. ((/Doc/English/WikiConcept Description of wiki concepts))
5. ((/Doc/English/Formatting Wacko-Markup Syntax))
8. ((https://c2.com/cgi/wiki?TextFormattingExamples 经典标记示例)) (载于 c2.com)
9. ((/Doc/English/WikiName WikiName)) —— 维基链接的概念