“写笔记”支持四种格式——Word 文档、Excel 表格、Markdown、纯文本,起稿或二次编辑时都能随时切换,同一篇笔记想用哪种形态来记,都由你说了算。
md、txt、csv、json 这类纯文本则原样载入,不做多余加工。拿一张现成的表倒进来、改几笔、再导出去,等于白用一台免费的格式转换器。
要带走就在右上角点“下载”,可导出 PDF、Word、Markdown、Excel、TXT 等格式;列表卡片“⋯”菜单里,也有同样的下载入口。
在“工具”页点“+ 上传工具”即可发布:填好名称与链接,再用 Markdown 把使用方法写清楚——能解决什么问题、怎么装、怎么用,比堆介绍实在。
要分发安装包就一并上传压缩包(ZIP、RAR、7Z、TAR.GZ,最大 35MB),别人在详情页一键下载;只放链接不带附件也可以。
工具按大家的收藏热度排序,好用的自然会被顶上来。发布后可在详情页或卡片菜单里编辑、下架。
写笔记时勾上“隐藏”,这篇就只存在于你自己的账号里:不进列表、不进搜索、不上首页精选,也不会出现在任何公开的页面,链接发给别人同样打不开。
适合放密码、草稿、日记这类只给自己看的内容;想公开,去“发布”打开它,把“隐藏”的勾去掉再保存,之后编辑会默认保持原状态,不会悄悄变回公开。
你的内容会同时保存在多个副本上,系统定期做备份与完整性校验,再配合异地容灾机制:就算某台机器出问题,数据也不会丢,可以长期放心存放;特别重要的资料,仍建议你另外再留一份备份。
全站跑在容器化、模块化的现代架构上,更新、部署、回滚都很快,扩展性和稳定性都按长期运营的标准来设计(Built for reliability, designed to scale)。
这个网站最早只是一个人的笔记仓库,后来慢慢长成现在的知识中枢。设计上很克制——没有广告、没有追踪、没有推荐算法,只是干干净净地存放一些东西;既然做好了,就公开出来,万一有人用得上呢。
不做大而全,不做平台梦,保持简单、保持克制、保持好奇。所有内容都由用户贡献、由用户维护:不会突然冒出付费墙,不会在角落塞广告位,也不会把你的数据卖给第三方。
产品会持续迭代,站内日志页记录着每一次改动,改了什么都有迹可循;想了解这个站是怎么一步步走到今天的,翻翻日志就能看到来龙去脉。
如果在这里看到涉嫌违规的内容,点对应卡片右侧的“举报”按钮就能提交,我们会尽快核实处理;也谢谢你花一点时间,一起把这里维护干净。
Pandoc Lua 过滤器:零依赖的高效文档转换利器
本文介绍 Pandoc 内置的 Lua 过滤器,它允许用户用 Lua 脚本直接操作文档的抽象语法树(AST),无需外部依赖且性能接近原生。
引言
Pandoc 是一个强大的文档格式转换工具,长期以来支持过滤器(filter)机制,允许用户在解析(parsing)和写入(writing)阶段之间操作 Pandoc 的抽象语法树(AST)。传统的 Pandoc 过滤器接收 JSON 格式的 AST 表示,并输出修改后的 JSON 表示。这些过滤器可以用任何编程语言编写,并通过 --filter 选项调用。
虽然传统过滤器非常灵活,但它们有两个主要缺点:
- 性能开销:将 JSON 写入 stdout 并从 stdin 读取(在过滤器两侧各一次)会产生显著的额外开销。
- 环境依赖:过滤器能否工作取决于用户环境的细节。例如,过滤器可能需要特定编程语言的解释器以及用于操作 JSON 形式 Pandoc AST 的库。这意味着不能简单地提供一个过滤器给所有拥有特定版本 Pandoc 可执行文件的用户使用。
Lua 过滤器的优势
从 Pandoc 2.0 版本开始,Pandoc 支持用 Lua 编写过滤器,且无需任何外部依赖。Pandoc 可执行文件中内置了一个 Lua 5.4 解释器和一个用于创建 Pandoc 过滤器的 Lua 库。Pandoc 数据类型直接映射到 Lua,避免了通过管道读写 JSON 的开销。
性能对比
以下是使用相同功能的过滤器(将强强调转换为小型大写字母)转换 Pandoc 手册(MANUAL.txt)为 HTML 的性能对比:
| 命令 | 时间 |
|---|---|
pandoc |
1.01s |
pandoc --filter ./smallcaps(编译的 Haskell) |
1.36s |
pandoc --filter ./smallcaps.py(解释型 Python) |
1.40s |
pandoc --lua-filter ./smallcaps.lua |
1.03s |
从数据可以看出,Lua 过滤器避免了通过管道进行 JSON 编组带来的大量开销,性能几乎与原生 Pandoc 持平(仅差 0.02 秒),而 JSON 过滤器则额外增加了约 35%-40% 的时间。
Lua 过滤器基础结构
Lua 过滤器本质上是 Lua 表(table),表的键是元素名称,值是对应元素的操作函数。过滤器应放在单独的文件中,通过 --lua-filter 命令行参数传递。
基本示例
以下是一个将强强调(Strong)转换为小型大写字母(SmallCaps)的 Lua 过滤器:
lua
return {
Strong = function(elem)
return pandoc.SmallCaps(elem.content)
end,
}
或者等价地:
lua
function Strong(elem)
return pandoc.SmallCaps(elem.content)
end
这两段代码的含义是:遍历 AST,当遇到 Strong 元素时,将其替换为具有相同内容的 SmallCaps 元素。
使用时,将上述代码保存到文件(例如 smallcaps.lua),然后运行:
bash
pandoc --lua-filter=smallcaps.lua input.md -o output.html
多过滤器应用
--lua-filter 选项可以多次使用。Pandoc 会按照命令行上出现的顺序依次应用所有过滤器(包括通过 --filter 指定的 JSON 过滤器和通过 --lua-filter 指定的 Lua 过滤器)。
过滤器的返回值
Pandoc 期望每个 Lua 文件返回一个过滤器。如果脚本没有显式返回值,Pandoc 会尝试收集所有顶层函数(其名称与 Pandoc 元素名称对应,如 Str、Para、Meta、Pandoc)来生成一个过滤器。这就是为什么上面两个例子是等价的。
在 walk 方法可用之前,从 Lua 文件返回一个过滤器列表是运行多个过滤器的唯一方式。但现在不推荐这种做法,建议使用 walk 方法,且此功能可能会在未来被移除。
过滤器函数详解
对于每个过滤器,文档会被遍历,每个元素都会经过过滤器的处理。如果过滤器包含某个元素类型的条目(即同名的函数),则该元素会被传递给对应的 Lua 元素过滤函数。
返回值要求
过滤函数的返回值必须是以下之一:
nil:表示对象保持不变。- 一个 Pandoc 对象:必须与输入类型相同,将替换原始对象。
- 一个 Pandoc 对象列表:这些对象将替换原始对象;列表会与原始对象的相邻元素合并(拼接到原始对象所属的列表中);返回空列表则删除该对象。
重要:函数的输出必须与输入类型相同。这意味着:
- 作用于内联元素的过滤函数必须返回
nil、一个内联元素或内联元素列表。 - 作用于块级元素的过滤函数必须返回
nil、一个块级元素或块级元素列表。
如果违反此条件,Pandoc 会抛出错误。
回退函数
如果某个元素节点类型没有匹配的函数,过滤系统会寻找更通用的回退函数。支持两个回退函数:
Inline:匹配所有内联元素。Block:匹配所有块级元素。
没有匹配函数的元素将保持原样。
元素序列过滤器
对于某些过滤任务,需要了解元素在文档中的顺序,仅检查单个元素是不够的。为此,Pandoc 提供了两个特殊函数名,用于定义块列表或内联列表上的过滤器。
Inlines(inlines)
如果过滤器中存在此函数,它将被调用到所有内联元素列表上,例如 Para(段落)块的内容,或 Image 的描述。inlines 参数是一个 List 类型的 Inline 元素列表。
Blocks(blocks)
如果过滤器中存在此函数,它将被调用到所有块元素列表上,例如 MetaBlocks 元元素块的内容、列表的每个项目以及 Pandoc 文档的主要内容。blocks 参数是一个 List 类型的 Block 元素列表。
特殊规则:这些过滤函数的结果必须要么是 nil(保持列表不变),要么是正确类型的列表(即与输入参数类型相同)。不允许返回单个元素,因为单个元素在此上下文中通常暗示 bug。
此功能从 Pandoc 2.9.2 版本开始支持。
遍历顺序
过滤器的遍历顺序可以通过设置 traverse 键来选择,可选值为 'topdown'(自上而下)或 'typewise'(按类型),默认是 'typewise'。
lua
local filter = {
traverse = 'topdown',
-- ... 过滤函数 ...
}
return filter
此功能从 Pandoc 2.17 版本开始支持,旧版本会忽略此设置。
按类型遍历(Typewise)
在按类型遍历模式下,过滤器集合中的元素过滤函数按固定顺序调用,跳过不存在的函数:内联元素函数 → Inlines 过滤函数 → 块元素函数 → Blocks 过滤函数 → Meta 过滤函数 → Pandoc 过滤函数。
可以通过手动使用 walk 方法强制改变顺序。例如,如果要在 Str 之前运行 Meta 过滤器,可以这样写:
lua
function Pandoc(doc)
doc = doc:walk { Meta = Meta } -- (1) 先处理 Meta
return doc:walk { Str = Str } -- (2) 再处理 Str
end
自上而下遍历(Topdown)
自上而下遍历更自然地从根节点向叶子节点进行深度优先遍历,且一次性完成。例如,对于块列表 [Plain [Str "a"], Para [Str "b"]],过滤函数将按以下顺序被调用:Blocks、Plain、Inlines、Str、Para、Inlines、Str。
自上而下遍历可以通过从过滤函数返回 false 作为第二个值来提前终止。在这种情况下,返回的元素的子元素将不会被处理。例如,要排除脚注内容被处理:
lua
traverse = 'topdown'
function Note(n)
return n, false
end
这样,脚注节点本身会被返回,但其子元素不会经过任何进一步的过滤处理。
实际应用场景
Lua 过滤器的强大之处在于其轻量级和灵活性。常见应用包括:
- 格式转换:将 Markdown 中的特定语法转换为其他格式(如自定义的强调样式)。
- 内容修改:自动添加或修改文档中的元数据、链接、图片等。
- 代码块处理:对代码块进行语法高亮、行号添加或自定义渲染。
- 数学公式:转换或预处理 LaTeX 数学公式。
- 自定义扩展:实现 Markdown 标准之外的语法扩展。
总结
Pandoc 的 Lua 过滤器提供了一种零外部依赖、高性能且灵活的文档转换机制。通过直接操作 AST,避免了 JSON 编组的开销,同时利用内置的 Lua 解释器消除了环境依赖问题。无论是简单的样式替换还是复杂的文档重组,Lua 过滤器都能以接近原生的性能高效完成任务。
对于需要频繁进行文档格式转换和定制的用户,掌握 Lua 过滤器是提升工作效率的关键技能。