面向产品经理的Emacs教程:34. Emacs里的表格

· 2527字 · 6分钟

1 课程回顾 🔗

通过上节课,我们学习了如何升级 Emacs 的插件,以及遇到报错应该如何处理。

今天我们来学习 Emacs 里的表格。

2 概述 🔗

Emacs 里是否可以处理表格?当然可以。尤其是 Org-mode,被称为文本界的 Office 套件,必须可以处理表格。今天我们来学习 Emacs 里的表格。

今天的主要内容有:

  • 创建表格
  • 导出表格
  • 表格公式

3 Emacs里的表格 🔗

3.1 table.el 🔗

Emacs 自带 table.el 包,可以处理纯文本表格,比如我们可以通过 table-insert 命令在当前光标处插入一个表格:

我们可以通过 <TAB> 键在不同的单元格里移动和编辑。

如果要使用这个包,需要注意以下几点:

  1. 你需要使用等宽字体,或调整好你的中英文字体大小比例,这样不至于表格会错乱不对齐
  2. 插入的表格,不依赖于文件格式,在任何缓冲区都可以插入,可以理解为类似于像 ASCII 艺术的那种感觉
  3. table.el 更关注的是文本表格的视觉布局和组织,不支持公式等复杂功能

3.2 org-table.el 🔗

下面讲一讲更加实用的 org-table.el 包,这个包是 Org-mode 官方支持的表格功能,它几乎能做到 Office 里做到的事,区别在于它是基于纯文本的,而 Office 不是。

你问我?我当然更加喜欢基于纯文本的 Org-mode,如果不是要和其他人协作,我甚至可能会卸载 Office。

下面就简单讲一讲 Org-mode 里的表格操作。

3.2.1 表格基本操作 🔗

3.2.1.1 创建表格 🔗

我自己创建表格用的是 yasnippet 的模板,只需要输入 <ta 再按下 <tab> 键,Emacs 就会自动在 Org 文档里创建一个表格:

这个 yasnippet 的模板如下:

# -*- mode: snippet -*-
# name: table
# key: <ta
# --
#+CAPTION: $1
#+NAME: ${1:tablename}
#+ATTR_LATEX: :float nil :environment tabularx :width \textwidth :align
| ${2:key} | ${3:description} |
|-$0
3.2.1.2 表格的编辑 🔗

我自己常用的表格编辑动作如下,供参考:

表 1: Emacs Org mode 表格常用编辑动作
快捷键 函数 作用
<tab> org-cycle 进入下一个单元格,同时可以自动调整表格格式
<backtab> org-shifttab 进入上一个单元格,同时可以自动调整表格格式
C-c C-c org-ctrl-c-ctrl-c 自动调整表格格式
RET org-return 进入下一行
C-c RET org-ctrl-c-ret 在当前行下加一行分隔线和新行然后移动到新行
C-c - org-ctrl-c-minus 在当前行下加一行分隔线
M-up org-metaup 交换当前行和上一行
M-down org-metadown 交换当前行和下一行
M-left org-metaleft 交行当前列和左边一列
M-right org-metaright 交换当前列和右边一列
M-S-up org-shiftmetaup 删除当前行
M-S-down org-shiftmetadown 在当前位置新增空行并将当前行下移一行
M-S-left org-shiftmetaleft 删除当前列
M-S-right org-shiftmetaright 在当前位置新增空列并将当前列右移一列
org-table-blank-field 清空当前单元格
M-a org-backward-sentence 跳转到当前单元格首
M-e org-forward-sentence 跳转到当前单元格尾
C-<tab> org-ctrl-c-tab 折叠或展开当前列
C-c ' org-edit-special 在一个新buffer输入表格公式
C-c = org-table-eval-formula 在当前单元格输入公式
C-c * org-ctrl-c-star 重新按照公式计算和更新表格
C-c } org-table-toggle-coordinate-overlays 是否显示表格的参考线更便于编写公式

3.2.2 表格公式 🔗

下面着重说下Org mode里表格的公式。

3.2.2.1 如何引用行、列、分隔线和单元格 🔗
  • @# 来表示第几行:如 @1 表示第一行, @0 表示当前行
  • @> 来表示最后一行
  • @< 来表示第一行
  • @+3 来表示当前行后3行: @-2 表示当前行前2行
  • $数字 来表示第几列:如 $1 表示第一列, $0 表示当前列
  • $> 来表示最后一列
  • $< 来表示第一列
  • $+3 来表示当前列后3列: $-2 表示当前列前2列
单元格
  • @#$# 来表示第几行第几列的单元格,如 @2$3 表示第二行第三列
  • @0$0 表示当前单元格
分隔线
  • @I 表示第一个水平分隔线,用 @II 表示第二个, @III 表示第三个
  • @-I 表示在当前行上一个水平分隔线, @+I 表示当前行下一个水平分隔线
  • @III+2 表示在第三个水平分隔线后2行
范围
  • .. 表示范围,如 @2..@> 表示第2行到最后一行
结果的格式
  • ;xx 来表示结果的格式规定,如 ;%.1f 表示保留到小数点后1位
3.2.2.2 常用例子 🔗

Org-mode 的表格支持两种公式,我们先讲 calc 格式或 elisp 的代码公式,我们可以根据需要灵活运用。

3.2.2.2.1 求平均 🔗

假设我们的原始表格如下:

表 2: 测试表格1
年份 销售额
2020 135
2021 150
2022 175
2023 160
平均

那么我们如何来写这个公式呢,我们可以将光标放到总计对应的那个空单元格,然后按下 C-c ' 后编辑公式: @>$2=vmean(@I$2..@II$2) , 编辑完后,表格就变成了如下:

| 年份 | 销售额 |
|------+--------|
| 2020 |    135 |
| 2021 |    150 |
| 2022 |    175 |
| 2023 |    160 |
|------+--------|
| 平均 |        |
#+TBLFM: @>$2=vmean(@2$2..@5$2);%.1f

我们可以使用 ;%.1f 来表示公式计算后的格式,如这个代表精确到小数点后一位。

然后我们在最后一个单元格里按下 C-c * (或将光标移动到公式行按 C-c C-c ) 就可以得到最终结果了:

年份 销售额
2020 135
2021 150
2022 175
2023 160
平均 155.0
3.2.2.2.2 求和 🔗

还是针对上面的表格,求和的公式为 @>$2=vsum(@I$2..@II$2)

最终的结果为:

年份 销售额
2020 135
2021 150
2022 175
2023 160
平均 620
3.2.2.2.3 单元格拼接 🔗

针对上面那个表格,如果我们想要增加一列,新的列由左边两列拼接而来,如 2020年的销售额为135万 ,此时编辑公式为 (concat $1 "年的销售额为" $2 "万")

最终的结果为:

年份 销售额 新的文本
2020 135 2020年的销售额为135万
2021 150 2021年的销售额为150万
2022 175 2022年的销售额为175万
2023 160 2023年的销售额为160万
3.2.2.2.4 多个公式 🔗

如果有多个公式,在 #+TBLFM: 的公式一行,通过 :: 将多个公式连接起来,如下:

| 年份 | 销售额 | 拼接的文本  |
|------+--------+-------------|
| 2020 |    160 | 2020年160万 |
| 2021 |    150 | 2021年150万 |
| 2022 |    175 | 2022年175万 |
| 2023 |    160 | 2023年160万 |
|------+--------+-------------|
| 平均 | 161.25 |             |
| 总计 |    645 |             |
#+TBLFM: @>>$2=vmean(@I$2..@II$2)::@>$2=vsum(@I$2..@II$2)::@2$3..@5$3='(concat $1 "年" $2 "万")

基本上学会上面这些常用的公式,能解决日常工作的大部分问题了,如果还有别的诉求,可以详细阅读 Org-mode 的官方文档

3.2.3 列表表格 🔗

我们在日常工作中,还会遇到一个诉求,就是更加复杂的表格,例如:

  • 在一个单元格里放一张图片
  • 在一个单元格里放一些项目符号
  • 在一个单元格里放多个段落文本

上述诉求,用常规的 org-table.el 是无法实现的,此时,我们需要 org-mode-ox-odt 这个包的帮助。

3.2.3.1 安装配置 🔗
(add-to-list 'package-archives
             '("ox-odt" . "https://kjambunathan.github.io/elpa/"))

(use-package ox-odt
  :ensure t
  :after (org ox ox-html)
  :init
  (add-to-list
   'org-export-filter-parse-tree-functions
   (defun org-html--translate-list-tables (tree backend info)
     (if (member backend '(html latex))
         (org-odt--translate-list-tables tree backend info)
       tree)))
  )
3.2.3.2 如何使用 🔗

安装完这个包后,我们就可以通过 list table (列表表格)来构建复杂的表格了。下面是一个示例:

#+CAPTION: 示例列表表格
#+NAME: 示例列表表格
#+ATTR_ODT: :list-table t
-
  - 标题1
  - 标题2
  - 标题3
- ----------------
  - 2007
  -
    - 很好
    - 非常好
    - 特别好
  -
    - [ ] 待办1
    - [ ] 待办2
    - [ ] 待办3
- ---------------
  -
     噼里啪啦第一段话

     噼里啪啦第二段话
  -
     [[https://orgmode.org/resources/img/org-mode-unicorn.svg]]
  -
     | 标题1 | 标题2     |
     |-------+-----------|
     |  2008 | good      |
     |  2010 | wonderful |

然后在我们按下 C-c C-e 选择 html 的格式进行导出的时候,可以看到这个复杂表格已经按照我们的预期生成了:

4 结语 🔗

通过今天的学习,我们了解了在 Emacs/Org-mdoe 内的表格,我们了解到如何在 Org-mode 里处理复杂一点的表格,如何使用公式,如何通过列表表格来生成更加复杂的表格,Org-mode 简直就是纯文本界的 Office!

这节课的配置文件的快照见:emacs-config-l34.org

你也可以在 这里 查看最新的配置文件。