旧版本的 Hugo 使用名为 Blackfriday 的库将 Markdown 转换为 HTML,这与 CommonMark 不兼容(与新版本 Hugo 中的 Goldmark 不同)。 Blackfriday 的一个问题是块引号内的空行被视为块引号的一部分。例如,
> One > Two
将转换为:
<blockquote> <p>One</p> <p>Two</p> </blockquote>
根据 CommonMark 规范,由于存在空行,应将其转换为两个块引号:
<blockquote> <p>One</p> </blockquote> <blockquote> <p>Two</p> </blockquote>
要生成单个块引用,空行也必须以>
开头。
我的很多旧帖子都有这个问题。我想这可能可以通过 Pandoc (Lua) 过滤器来解决,但我不需要严格的要求,所以我编写了一个 R 函数来处理我的 Markdown 文件(就像上次一样):
# add > to empty lines to merge consecutive blockquotes merge_bq = function(x) { if ((n <- length(x)) < 3) return(x) r = '^(>( >)* ?)(.*)$' i = grep(r, x) if (length(i) < 2) return(x) # exclude consecutive lines that start with > i = i[c(diff(i) > 1, TRUE)] if ((n <- length(i)) < 2) return(x) for (k in 1:(n - 1)) { i1 = i[k]; i2 = i[k + 1] # from line #i1 on, a line should not be blank unless # the rest of lines are all blank till line #i2 i3 = (i1 + 1):(i2 - 1) b = xfun::is_blank(x[i3]) if (any(b) && !all(tail(b, -which(b)[1]))) next p = sub(r, '\\1', x[i1]) # '> ' (or nested '> > ...') p = sub(' *$', ' ', p) # ensure trailing space x[i3] = paste0(p, x[i3]) } x }
该代码远非优雅或易于理解。尽管如此,我还是在这里留下了一个记录,因为我在我的职业生涯中写过很多这样的愚蠢代码。我不想假装我总是在编写优雅的代码。相反,我写的大部分代码可能都是相当愚蠢和无聊的。
最近,我与 JMP 的 Peng Liu 谈论了我们的软件开发职业,因为他希望组织一次关于这个主题的 JSM 会议(不幸的是,没有成功)。虽然我不打算参加 JSM,但我想了一会儿,如果我要发表演讲,我可以分享什么。我想到的一件事是,我们需要多少正规的计算机科学培训才能成为一名成功的软件工程师。我之所以这么想,是因为我没有接受过任何正规的培训,对算法也不太了解。如果我要找一份软件开发工作,我想我会因为我对计算机科学的了解而立即被拒绝。
但我可以编写for
循环(小心和耐心)并使用正则表达式。我觉得我一直靠它们谋生(谢天谢地,冒名顶替综合症无法打败我)。通常我写代码很慢,因为我的大脑很慢。上面的for
循环花了我将近两个小时。在我看来,我只是在处理几行文本——有些以>
开头,有些是空白。
一些快速测试:
merge_bq(c('> a', '', '> b'))
> a > > b
merge_bq(c('> a', 'c', '', '> b'))
> a > c > > b
merge_bq(c('> a', '', 'c', '> b'))
> ac > b
merge_bq(c('> a', '', '> > c', '', 'd', '', '> b'))
> a > > > cd > b
merge_bq(c('> a', '', '> > c', 'd', '', '', '> b'))
> a > > > c > > d > > > > > b
一切看起来都不错,所以我批量处理了我的所有帖子:
# process all writable [R]md files files = blogdown:::list_rmds(pattern = blogdown:::md_pattern) files = files[file.access(files, 2) == 0] # writable for (f in files) xfun::process_file(f, merge_bq)
感谢 Git,我可以在提交更改之前对更改进行手动检查(我确实恢复了一些更改,因为空行实际上意味着块引用分隔符)。