在 Markdown 中稳健地生成锚点

Robustly generate anchors in Markdown

我有一些 Ruby 代码可以在 GitHub Flavored Markdown 中自动生成目录。如果与此问题相关的差异,最好也了解其他 Markdown 风格。

目前,我的这段代码在 99% 的时间内都有效:

  def header_to_anchor
    @header
      .downcase
      .gsub(/[^a-z\d\- ]+/, "")
      .gsub(/ /, "-")
  end

这是基于我在 GitHub 评论 here 中发现的注释。上面写着:

The code that creates the anchors is here: https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/toc_filter.rb

  1. It downcases the string
  2. remove anything that is not a letter, number, space or hyphen (see the source for how Unicode is handled)
  3. changes any space to a hyphen.
  4. If that is not unique, add "-1", "-2", "-3",... to make it unique

为了我的目的,我不需要解决唯一性问题。

这很棒,直到我发现另一个失败的边缘案例,即我在降价文档中有一个标题:

### shunit2/_shared.sh

我的代码生成的锚是:

* [shunit2/_shared.sh](#shunit2sharedsh)

并创建另一个损坏的 link,至少就 GitHub Flavored Markdown 而言是这样。

我在这里也看到了 this 的回答,但是那里指定的那些规则似乎也不太可靠。

有谁知道解释这些锚点生成规则的权威文档吗?

好吧,这里的混淆出现了1 GitHub 注释中提到的代码中的 Ruby 正则表达式与评论说。该代码使用此正则表达式:

PUNCTUATION_REGEXP = RUBY_VERSION > '1.9' ? /[^\p{Word}\- ]/u : /[^\w\- ]/

删除"punctuation"。 Ruby 正则表达式已记录 here

同时,\p{Word}实际上表示字母数字加下划线

因此,GitHub 问题中的评论,“删除任何不是字母、数字、space 或连字符的内容(请参阅源代码了解如何处理 Unicode )”是对代码的误读。

正确的规则应该是:

  1. It downcases the string
  2. Remove anything that is not a letter, number, space, underscore or hyphen (see the source for how Unicode is handled)
  3. Change any space to a hyphen.
  4. If that is not unique, add "-1", "-2", "-3",... to make it unique

1 当然,假设 GitHub 问题中提到的 toc_filter.rb 文件确实是 "source of truth" 而不是实现其他地方定义的规则。