andrewheiss/quarto-wordcount
GitHub: andrewheiss/quarto-wordcount
Quarto 扩展用于解决学术写作中字数统计不准与格式兼容问题,在渲染后精确计算正文、摘要、参考文献及附录字数。
Stars: 144 | Forks: 8
# Quarto 字数统计
- [实验性新功能!](#experimental-new-feature)
- [为什么计算字数很难](#why-counting-words-is-hard)
- [使用字数统计脚本](#using-the-word-count-script)
- [安装](#installing)
- [用法](#usage)
- [终端输出](#terminal-output)
- [短代码](#shortcodes)
- [不计入统计](#no-counting)
- [代码块](#code-blocks)
- [附录](#appendices)
- [示例](#example)
- [致谢](#credits)
- [它是如何工作的](#how-this-all-works)
## 实验性新功能!
## 为什么计算字数很难
在学术写作和出版中,字数统计很重要,因为
许多期刊对提交的稿件有字数限制。计算 Quarto Markdown 文件中的字数很棘手,原因有以下几点:
1. **与 Word 的兼容性**:学术出版门户往往关注类似 Microsoft Word 的字数统计,但许多用于计算文档字数的 R 和 Python 函数对单词边界的处理方式不同。
例如,Word 认为连字符单词是一个单词(例如,“A super-neat kick-in-the-pants example”是 4 个单词),而 `stringi::stri_count_words()` 将其计为多个单词(例如,“A super-neat kick-in-the-pants example”在使用 {stringi} 时为 8 个单词)。
更糟糕的是,{stringi} 将“/”视为单词边界,因此 URL 可能会严重夸大实际字数。
2. **额外的文本元素**:学术写作通常不将标题、摘要、表格文本、表格和图形标题或公式计入稿件字数。
在 Quarto Markdown 这样的计算文档中,这些内容在文档渲染之前通常不会出现,因此简单地对 `.qmd` 文件运行字数统计函数会计算生成表格和图形的代码,再次导致字数膨胀。
3. **引用和参考文献**:学术写作通常将参考文献计入字数(尽管实际上不应该)。
然而,在 Quarto Markdown(以及其他基于 pandoc 的 Markdown)中,引用在生成参考文献之前不会被计入字数。
简单地对 `.qmd` 文件(或者类似超整洁的
[{wordcountaddin}](https://github.com/benmarwick/wordcountaddin))
运行字数统计函数只会看到文档中的 citekeys,例如 `@Lovelace1842`,但只会将其作为独立单词计数(例如,不是“(Lovelace 1842)”这种内文格式或“Ada Augusta Lovelace, “Sketch of the Analytical Engine…,” *Taylor's Scientific Memoirs* 3 (1842): 666–731.”这种脚注格式),更重要的是,它不会计入最终参考文献列表中自动生成的任何引用。
这个扩展通过依赖一个 [Lua 过滤器](_extensions/wordcount/wordcount.lua) 来在文档渲染完成后、转换为最终输出格式之前统计字数,解决了以上三个问题。
[Frederik Aust (@crsh)](https://github.com/crsh)
在 R Markdown 文档中使用相同的 Lua 过滤器进行字数统计,并结合
[{rmdfiltr}](https://github.com/crsh/rmdfiltr)
软件包(实际上我只是复制并略微扩展了[该软件包的](https://github.com/crsh/rmdfiltr/blob/master/inst/wordcount.lua)
`inst/wordcount.lua`)。
该过滤器效果很好,并且[大致可与 Word 的字数统计](https://cran.r-project.org/web/packages/rmdfiltr/vignettes/wordcount.html)相比。
你最好浏览一下[“它是如何工作的”](#) 章节以了解……嗯……它是如何工作的。
## 使用字数统计脚本
### 安装
```
quarto add andrewheiss/quarto-wordcount
```
{quarto-wordcount} 需要 Quarto 版本 \>= 1.4.551。
这将在 `_extensions` 子目录下安装扩展。如果使用版本控制,请将此目录纳入版本管理。
### 用法
启用扩展有两种方式:(1) 作为输出格式,(2) 作为过滤器。
#### 输出格式
可以在 YAML 设置中指定四种不同的输出格式:`wordcount-html`、`wordcount-pdf`、`wordcount-docx`:
```
title: Something
format:
wordcount-html: default
```
`wordcount-FORMAT` 格式类型实际上只是每种基础格式(HTML、PDF、Word 和 Markdown)的包装器,因此所有其他 HTML、PDF、Word 和 Markdown 特定选项都会像往常一样工作:
```
title: Something
format:
wordcount-html:
toc: true
fig-align: center
cap-location: margin
```
#### 过滤器
如果使用的是 [自定义输出格式](https://quarto.org/docs/extensions/listing-formats.html)(例如
[{hikmah-academic-quarto}](https://github.com/andrewheiss/hikmah-academic-quarto)
或 [期刊文章格式](https://quarto.org/docs/extensions/listing-journals.html) 如
[{jss}](https://github.com/quarto-journals/jss)),则无法使用 `wordcount-html` 格式,因为不能组合输出格式。
要为 *任何* 格式(包括自定义格式)启用字数统计,可以将扩展 Lua 脚本作为过滤器添加。需要指定三个设置:
1. 必须设置 `citeproc: false`,以防止 Quarto 尝试处理引用;
2. 引用处理所需的 `citeproc.lua` 路径,因此它必须在 `wordcount.lua` [之前执行](#how-this-all-works);
3. 字数统计所需的 `wordcount.lua` 路径。
```
title: Something
format:
html: # Regular built-in format
citeproc: false
filters:
- at: pre-quarto
path: _extensions/andrewheiss/wordcount/citeproc.lua
- at: pre-quarto
path: _extensions/andrewheiss/wordcount/wordcount.lua
jss-pdf: # Custom third-party format
citeproc: false
filters:
- at: pre-quarto
path: _extensions/andrewheiss/wordcount/citeproc.lua
- at: pre-quarto
path: _extensions/andrewheiss/wordcount/wordcount.lua
```
### 终端输出
字数统计结果将在渲染文档时显示在终端输出中。它在三个部分中显示多个值:
- **文稿总计**:(1) 正文、注释和参考文献的总字数,(2) 仅正文和注释的字数,以及(如果存在附录)(3) 正文、注释、参考文献和附录的总字数。
我通常合作的期刊会将正文 + 注释 + 参考文献计入总字数。在压缩稿件以符合字数限制时,将参考文献与正文 + 注释分开有助于我更清晰地判断哪里可以最有效地编辑(例如,是改写句子还是删除参考文献)。
- **具体总计**:正文、注释、参考文献和附录的字数统计。
- **总体总计**:包括摘要在内的所有内容(1)以及仅摘要(2)的字数统计。
这里包含摘要总计,是因为摘要通常不计入实际稿件字数限制,但仍需统计,因为它通常有独立的字数限制。
```
Manuscript totals:
---------------------------------------------------
- 458 words (text + notes + references)
- 405 words (text + notes)
- 478 words (text + notes + appendix + references)
Specific totals:
---------------------------------------------------
- 315 words in text body
- 90 words in notes
- 53 words in references
- 20 words in appendix
Overall totals:
---------------------------------------------------
- 484 words in entire document
- 6 words in abstract
```
### 短代码
还可以在文档中直接使用多个短代码来包含不同的字数统计:
- 使用 `{{< words-total >}}` 包含所有字数统计;
- 使用 `{{< words-body >}}` 仅包含正文中的字数统计,不包括参考文献、注释和附录;
- 使用 `{{< words-ref >}}` 包含参考文献部分的字数统计;
- 使用 `{{< words-append >}}` 包含附录部分的字数统计,附录必须包含在 `id="appendix-count"` 的分隔 div 中
([更多细节请参见下文](#appendices));
- 使用 `{{< words-note >}}` 包含注释部分的字数统计;
- 使用 `{{< words-abstract >}}` 包含摘要部分的字数统计;
- 使用 `{{< words-sum ARG >}}`,其中 `ARG` 是五个可统计区域(`body`、`ref`、`append`、`note`、`abstract`)的某种组合。
例如,`{{< words-sum body-note >}}` 包含正文和注释的字数统计;`{{< words-sum ref-append >}}` 包含参考文献和附录的字数统计。
还可以在 YAML 元数据中使用短代码:
```
title: Something
subtitle: "{{< words-sum body-note-ref >}} words"
```
### 不计入统计
如果希望排除某些文本不计入字数统计,可以将其包含在带有 `{.no-count}` 类的 [fenced
div](https://quarto.org/docs/authoring/markdown-basics.html#sec-divs-and-spans) 中:
```
::: {.no-count}
These words don't count.
:::
```
### 代码块
默认情况下,代码块中的文本 ***会被计入***。例如,下面的内容:
```
---
title: "Code counting"
format: wordcount-html
---
This sentence has seven words in it.
```{r}
# 这是代码
numbers <- 1:10
mean(numbers)
```
```
……会产生以下字数统计结果:
```
Overall totals:
-----------------------------
- 16 total words
- 16 words in body and notes
Section totals:
-----------------------------
- 16 words in text body
```
……其中包含来自句子的 7 个单词和来自代码的 9 个单词。
可以通过 YAML 选项 `count-code-blocks` 禁用代码块计数:
```
---
title: "Code counting"
format:
wordcount-html:
count-code-blocks: false
---
This sentence has seven words in it.
```{r}
# 这是代码
numbers <- 1:10
mean(numbers)
```
```
……这将产生以下统计结果:
```
Overall totals:
----------------------------
- 7 total words
- 7 words in body and notes
Section totals:
----------------------------
- 7 words in text body
```
### 附录
在学术写作中,通常需要单独统计附录内容的字数,因为附录中的内容通常不计入期刊字数限制。Quarto 有一个很酷的功能,可以自动创建附录部分并在需要时自动移动内容。Quarto 使用(我)一个 Lua 过滤器来实现这一点。
然而,Quarto 的附录生成过程发生在任何自定义 Lua 过滤器之后,因此即使最终渲染的文档创建了一个 `id="appendix"` 的分隔 div,该 div 在统计字数时也还不可访问,因此无法轻松提取附录字数。
因此,作为(临时的?)变通方法(直到我弄清楚如何让这个 Lua 过滤器在创建附录 div 之后运行),你可以通过创建具有 `id="appendix-count"` 的自定义分隔 div 来获取独立的附录字数统计:
```
# 介绍
Regular text goes here.
::: {#appendix-count}
# 附录 {.appendix}
More words here
:::
```
## 示例
你可以在 [`template.qmd`](template.qmd) 中看到一个最小示例文档。
## 致谢
原始的 [`wordcount.lua`](_extensions/wordcount/wordcount.lua)
过滤器来自 [Frederik Aust 的 (@crsh)](https://github.com/crsh)
[{rmdfiltr}](https://github.com/crsh/rmdfiltr)
软件包。
## 它是如何工作的
在幕后,pandoc 通常会将 Markdown 文档转换为抽象语法树(AST),即一种与输出无关的文档元素表示形式。以 AST 形式,很容易使用 [Lua 语言](https://pandoc.org/lua-filters.html) 提取或排除文档的特定元素(即排除标题或仅查看参考文献)。
Quarto 被设计为与语言无关,因此 {rmdfiltr} 使用 R 在 YAML 前置事项中动态设置 Lua 过滤器路径的方法不适用于 Quarto 文件。([参见 Quarto 团队的评论](https://github.com/quarto-dev/quarto-cli/issues/1391#issuecomment-1185348644),指出你不能在 Quarto YAML 头部使用 R 输出。)
但仍然可以使用带有一点技巧的 {rmdfiltr} Lua 过滤器。
为了在字数统计中包含引用,我们必须将字数统计过滤器提供给已使用 [`--citeproc`
选项](https://pandoc.org/MANUAL.html#citation-rendering) 处理的文档版本。
然而,在 R Markdown/knitr 和 Quarto 中,`--citeproc` 标志被设计为最后一个选项,导致 pandoc 命令类似于:
```
pandoc whatever.md --output whatever.html --lua-filter wordcount.lua --citeproc
```
参数的顺序很重要,因此让 `--lua-filter wordcount.lua` 出现在 `--citeproc` 之前会导致在生成参考文献之前统计字数,这并不理想。
{rmdfiltr} 通过编辑 YAML 前置事项来绕过此顺序问题,以 (1) 禁用一般 citeproc 并 (2) 在运行过滤器之前指定 `--citeproc` 标志:
```
output:
html_document:
citeproc: false
pandoc_args:
- '--citeproc'
- '--lua-filter'
- '/path/to/rmdfiltr/wordcount.lua'
```
这将生成一个 pandoc 命令,类似于以下内容,其中 `--citeproc` 在前,因此生成的参考文献会被计入:
```
pandoc whatever.md --output whatever.html --citeproc --lua-filter wordcount.lua
```
但 Quarto 没有 `pandoc_args` 选项。相反,它有一个 `filters` YAML 键,允许你指定要在渲染过程特定步骤应用的 Lua 过滤器列表。
```
format:
html:
citeproc: false
filters:
- "/path/to/wordcount.lua"
```
然而,没有明显的方法可以重新定位 `--citeproc` 参数,它会自动出现在最后,导致生成的参考文献不被计入。
幸运的是,[这个 GitHub
评论](https://github.com/quarto-dev/quarto-cli/issues/2294#issuecomment-1238954661)
表明可以创建一个 Lua 过滤器,其行为类似于 `--citeproc`,通过将整个文档传递给 `pandoc.utils.citeproc()`。这意味着我们可以创建一个类似 `citeproc.lua` 的 Lua 脚本:
```
-- Lua filter that behaves like `--citeproc`
function Pandoc (doc)
return pandoc.utils.citeproc(doc)
end
```
……然后将其作为过滤器包含:
```
format:
html:
citeproc: false
filters:
- at: pre-quarto
path: "path/to/citeproc.lua"
- at: pre-quarto
path: "path/to/wordcount.lua"
```
这会生成一个 pandoc 命令,类似于以下内容,先将文档传递给 citeproc “过滤器”,然后再传递给字数统计脚本:
```
pandoc whatever.md --output whatever.html --lua-filter citeproc.lua --lua-filter wordcount.lua
```
标签:Markdown, Python, Quarto, R, rizin, Word Count, 二进制发布, 代码块计数, 字数统计, 字数统计工具, 字数限制, 学术写作, 开源工具, 引用计数, 扩展插件, 技术写作, 文本处理, 文档分析, 无后门