Skip to content

Commit 27176f9

Browse files
committed
feat: add word counter
Signed-off-by: Juntong Chen <[email protected]>
1 parent ff8a390 commit 27176f9

File tree

7 files changed

+102
-11
lines changed

7 files changed

+102
-11
lines changed

README.md

+39-3
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,20 @@
1111
- 优化段落缩进
1212
- 优化对多行标题 / 院系的处理逻辑
1313
- 优化开启 `twoside` 参数后的页码逻辑
14+
- 增加字数统计功能
1415

1516
对于研究生,我们参考华东师范大研究生院于 2023 年发布的[华东师范大学博士、硕士学位论文基本格式要求](https://yjsy.ecnu.edu.cn/8e/62/c42090a429666/page.htm);对于本科生,我们参考华东师范大学教务处于 2021 年更新的[华东师范大学本科生毕业论文(设计)格式要求](http://www.jwc.ecnu.edu.cn/d4/be/c40573a513214/page.htm)。格式适配于 2025 年初,后续使用的同学请留意参考校方的最新通知。
1617

1718
![1736471485839](https://jtchen.s3.ap-northeast-1.amazonaws.com/v1/img/2025/01/09/1736471485839.png)
1819

1920
在这里可以找到硕士学位论文的示例文档:[thesis.pdf](https://github.com/jtchen2k/modern-ecnu-thesis/releases/download/0.1.0/thesis.pdf)
2021

22+
## Why Typst
23+
24+
> 天下苦 LaTeX 久矣。
25+
26+
Typst 是一个基于 Rust 的现代化的排版引擎。它具备类似 Markdown 的简洁语法、清晰的错误提示、实时预览级的编译性能,又同时具备和 LaTeX 一样精准的排版控制和图灵完备的脚本能力。自 2023 年 4 月开源发布以来,已获得 ![](https://img.shields.io/github/stars/typst/typst?style=flat)。现代化的 Typst 可以让你更加专注于论文内容本身,而不被 LaTeX 漫长的编译时间与难以阅读的输出日志困扰。
27+
2128
## Usage
2229

2330
### 在 VSCode 中本地编辑(推荐)
@@ -66,16 +73,45 @@ ln -s </path/to/modern-ecnu-thesis> $DATA_DIR/typst/packages/preview/modern-ecnu
6673

6774
## Tips
6875

76+
默认模板有一些示例代码,清空前请留意。
77+
78+
### 字数统计
79+
80+
模板内置了字数统计功能。统计时会除去标题与标点符号,默认包括了正文与附录的所有内容。一个英语单词或一个 CJK 汉字将会被统计为一个 word,一个任意字符会被统计为一个 char。默认的统计范围为正文 + 附录,这取决于文中 `#show: word-count-cjk` 的位置。如果希望包括摘要、目录等能容,将这一行移动到 `#show: preface` 的下一行即可。
81+
82+
如需统计字数,可以使用 `make count` 命令,你会得到类似如下的输出:
83+
84+
```
85+
#word: 100
86+
#char: 200
87+
```
88+
89+
具体而言,该命令使用 `typst query` 命令来查询嵌入在 `mainmatter.typ` 里的包含字数信息的 `metadata`。你也可以在正文中使用 `total-words-cjk``total-characters` 或使用以下代码来显示总字数 / 字符数:
90+
91+
```typst
92+
context state("total-words-cjk").final()
93+
context state("total-characters").final()
94+
```
95+
96+
### 从 LaTeX 到 Typst
97+
6998
- Typst 支持的图片格式包括 png, jpeg, gif 与 svg,不支持 pdf 与 eps。你可以使用 InkSpace 或 [pdf2svg](https://github.com/dawbarton/pdf2svg) 等工具将 pdf 转换为 svg 格式:
7099

71100
```bash
72101
pdf2svg input.pdf output.svg
73102
```
74103

75-
- Typst 现在已经支持图片的浮动排版了。你可以使用 `figure``placement` 属性来控制图片位置。
76-
- Typst 有一套自己的公式语法,与 LaTeX 大同小异且更加简洁。如果你已经十分熟悉 LaTeX 的语法并希望使用,可以使用 [MiTeX](https://github.com/mitex-rs/mitex),它将允许你在 Typst 中使用 LaTeX 数学语法。
104+
- Typst 现在已经支持图片的浮动排版了。你可以使用 `figure``placement` 属性来控制图片位置,可以实现类似 LaTeX 的 `[htbp]` 功能:
105+
106+
```typst
107+
figure {
108+
placement: "top";
109+
caption: "image caption";
110+
...
111+
}[#image("...)] <label>
112+
```
113+
- Typst 有一套自己的公式语法,与 LaTeX 大同小异且更加简洁。如果你已经十分熟悉 LaTeX 的语法并希望继续使用,可以引入 [MiTeX](https://github.com/mitex-rs/mitex),它将允许你在 Typst 中使用 LaTeX 数学语法。
77114
- Typst 原生兼容了 biblatex 引用格式,直接修改 ref.bib 即可。
78-
- 默认模板有一些示例代码,清空前请留意。
79115
80116
更多 Typst 的介绍、学习资料与项目背景可参考[上游项目](https://github.com/nju-lug/modern-nju-thesis)的 README。
81117

layouts/appendix.typ

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#import "@preview/i-figured:0.2.4"
22
#import "../utils/custom-numbering.typ": custom-numbering
33

4+
45
// 后记,重置 heading 计数器
56
#let appendix(
67
numbering: custom-numbering.with(first-level: "", depth: 4, "1.1 "),

layouts/mainmatter.typ

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#import "../utils/indent.typ": fake-par
77
#import "../utils/unpairs.typ": unpairs
88
#import "../utils/pagebreak-from-odd.typ": pagebreak-from-odd
9+
#import "../utils/word-counter.typ": *
910

1011
#let mainmatter(
1112
// documentclass 传入参数
@@ -215,8 +216,15 @@
215216
)
216217
}))
217218

218-
it
219+
// 字数统计(正文 + 附录)
220+
// typst query main.typ '<total-words>' 2>/dev/null --field value --one
221+
222+
context [
223+
#metadata(state("total-words-cjk").final()) <total-words>
224+
#metadata(state("total-characters").final()) <total-chars>
225+
]
219226

227+
it
220228
// 正文结束标志,不可缺少
221229
// 这里放在附录后面,使得页码能正确计数
222230
fence()

lib.typ

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @project: modern-ecnu-thesis
55
* @author: OrangeX4, Juntong Chen ([email protected])
66
* @created: 2025-01-06 22:37:34
7-
* @modified: 2025-01-10 01:58:02
7+
* @modified: 2025-01-11 15:11:45
88
*
99
* 华东师范大学学位论文模板
1010
* Repo: https://github.com/jtchen2k/modern-ecnu-thesis
@@ -39,6 +39,7 @@
3939
#import "utils/custom-heading.typ": heading-display, active-heading, current-heading
4040
#import "utils/indent.typ": indent, fake-par, no-indent
4141
#import "utils/panic-page.typ": panic-page
42+
#import "utils/word-counter.typ": *
4243
#import "@preview/i-figured:0.2.4": show-figure, show-equation
4344
#import "utils/style.typ": 字体, 字号
4445

template/Makefile

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
TYP_SRC = $(shell find . -name '*.typ')
2+
23
TARGET = thesis.pdf
4+
TARGET_TYP = thesis.typ
35

46
$(TARGET): $(TYP_SRC)
5-
typst compile thesis.typ --pdf-standard 1.7 --root ..
7+
typst compile --pdf-standard 1.7 $(TARGET_TYP) --root ..
8+
@echo "Build successful: $(shell du -h $(TARGET_TYP) | cut -f1)"
69

7-
.PHONY: clean, watch
10+
.PHONY: clean, watch, count
811
clean:
912
rm -f $(TARGET)
1013

1114
watch:
12-
typst watch thesis.typ --root ..
15+
typst watch --root .. --pdf-standard 1.7 $(TARGET_TYP)
16+
17+
# Count words and characters in mainmatter and backmatter
18+
count:
19+
@echo "#words: $(shell typst query $(TARGET_TYP) '<total-words>' 2>/dev/null --field value --one)"
20+
@echo "#chars: $(shell typst query $(TARGET_TYP) '<total-chars>' 2>/dev/null --field value --one)"

template/thesis.typ

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#import "@preview/modern-ecnu-thesis:0.1.0": documentclass, indent, no-indent
1+
#import "@preview/modern-ecnu-thesis:0.1.0": documentclass, indent, no-indent, word-count-cjk, total-words
22

33
// 模板用到的主要字体:https://github.com/jtchen2k/modern-ecnu-thesis/tree/main/fonts/
44
// 如果是在 Web App 上编辑,你应该手动上传上述字体文件,否则不能正常使用「楷体」和「仿宋」。
@@ -109,6 +109,9 @@
109109
// 可选的,可以通过 #show: mainmatter.with(figure-clearance: 0pt) 来设置浮动图表的间距或其他参数
110110
#show: mainmatter
111111

112+
// 字数统计开始
113+
#show: word-count-cjk
114+
112115
= 导 论
113116

114117
== 列表
@@ -219,6 +222,15 @@ int main() {
219222

220223
#no-indent 比如,这是一个没有首行缩进的段落。
221224

225+
=== 字数统计
226+
227+
正文与附录的的总字数为:#total-words。你也可以使用以下命令来使用命令行工具统计字数 / 字符数:
228+
229+
```bash
230+
typst query thesis.typ '<total-words>' 2>/dev/null --field value --one
231+
typst query thesis.typ '<total-characters>' 2>/dev/null --field value --one
232+
```
233+
222234
= 正 文
223235

224236
// 用于生成占位符。可删除。
@@ -235,8 +247,6 @@ int main() {
235247
+ 自定义段落编号
236248
]
237249

238-
239-
240250
// 手动分页示例
241251
#if twoside {
242252
pagebreak() + " "

utils/word-counter.typ

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* word-counter.typ
3+
*
4+
* @project: modern-ecnu-thesis
5+
* @author: Juntong Chen ([email protected])
6+
* @created: 2025-01-11 13:37:30
7+
* @modified: 2025-01-11 15:12:07
8+
*
9+
* Copyright (c) 2025 Juntong Chen. All rights reserved.
10+
*/
11+
12+
#import "@preview/wordometer:0.1.4": *
13+
14+
#let word-count-cjk(content, ..options) = {
15+
let stats = word-count-of(content, exclude: (heading), counter: s => (
16+
characters: s.replace(regex("\s+"), "").clusters().len(),
17+
words: s.matches(regex("\b[\w'’.,\-]+\b")).len(),
18+
words-cjk: s.matches(regex("[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]|[\w''.,\-]+")).len(),
19+
), ..options)
20+
state("total-words-cjk").update((prev) => prev + stats.words-cjk)
21+
state("total-words").update((prev) => prev + stats.words)
22+
state("total-characters").update((prev) => prev + stats.characters)
23+
content
24+
}
25+
26+
#let total-words = context state("total-words-cjk").final()
27+
#let total-characters = context state("total-characters").final()

0 commit comments

Comments
 (0)