在Org-mode的电子表格中使用elisp公式

原文Org as a spreadsheet system: using Emacs lisp as formulas, 由 Bastien 编辑,维护。本文只做学习之用。

序言<a id="sec-"></a>

本教程介绍如何在Org表中使用Emacs Lisp作为公式。 如果想要了解如何使用Org作为电子表格系统的一般教程,请阅读这个教程。 还可以查看有关此主题的完整Org文档

示例 1: 操纵单元格<a id="sec-"></a>

下面是一个简单的表格:

First name Last Name Email
John Doe john.doe@emacs.edu
Jennie Duh jennie.duh@emacs.edu

你会很容易就注意到第三列模式: [firstname].[lastname]@emacs.edu 。 给出 First nameLast name ,很容易计算 Email 列的结果。

首先将光标放在第三列中:

现在键入 C-c } 显示表的坐标(引用)。

对于每一行,需要将第一列(使用 $1 访问)的内容连接到点("."),然后连接到第二列(使用 $2 访问)的单元格, 最后连接到字符串 "@emacs.edu"。 使用 Emacs Lisp 编写的公式如下所示:

'(concat (downcase $1) "." (downcase $2) "@emacs.edu")

现在复制这个公式,在右下角的字段中键入 C-c = 来插入列公式<a id="fnr.2" class="footref" href="#fn.2">2</a>,然后粘贴公式。 点击 RET 将立即将结果插入此单元格( jack.goody@emacs.edu ),并在表格的底部添加 #+TBLFM 行。

警告:请注意初始引用 ( initial quote ) :公式是表达式本身 (expression itself) ,而不是其值。 当 $1$2 引用将被正确的字符串替换时,该表达式将只有一个含义,然后通过在 #+TBLFM 上键入 C-c C-c 来应用该表达式。

经过公式计算表格如下:

在执行公式时, $1$2 将被解释并由这些单元格的值替换为字符串:不需要用 " 括起 $1

如果需要强制 $1$2 被解释为数字,请在 Emacs lisp 表达式的末尾添加标志 ;N 。 参见下面表格:

First name Last Name Maths French Mean
John Doe 12 16 14
Jennie Duh 15 9 12

使用如下公式计算第五列:

#+TBLFM: $5='(/ (+ $3 $4) 2);N

作为一个练习,尝试写出下面表第五列的Emacs lisp公式:

First name Last Name Maths French Mean
John Doe 12 16 John: 14
Jennie Duh 15 9 Jennie: 12

前四列的值是目前已知的,在此基础上构造出第五列。 (提示:参阅 Emacs lisp 函数 string-to-numbernumber-to-string 。)

解决方案 :不能使用 ;N 标志,因为它会强制将单元格解释为数字,如果这样做,将无法访问第一行单元格的值。 所以一个方案就是使用 string-to-numbernumber-to-string, 如下所示:

#+TBLFM: $5='(concat $1 ": " (number-to-string (/ (+ (string-to-number $3) (string-to-number $4)) 2)))

另一个解决方案是使用 ;L 标志:单元格内容不是被直接解释成字符串或数字,而是直接插入到 Emacs lisp 表达式中。 所以上面的公式可以安全地被下面这个更精简的代替:

#+TBLFM: $5='(concat "$1" ": " (number-to-string (/ (+ $3 $4) 2)));L

注意 "$1" 的双引号:因为在字面上插入 First name 将意味着 "it is an Emacs lisp symbol" 。 所以,当使用 ;L 标志时,添加双引号确保引用被解释为一个字符串。

示例 2: 操纵行列区间<a id="sec-"></a>

假设有以下表格

Col1 Col2 Col3 Col4 Col5
? ? in Col1 and Col2 (no duplicates) only in Col1 only in Col2
? ?
? ?

Col1Col2 包含字符串。

第三列的第一个单元格包含一个字符串,这个字符串由 Col1Col2 中的所有字符串去重后组成。 Col4 包含仅在 Col1 (不在 Col2 )中的字符串,而 Col5 包含仅在 Col2 (不在 Col1 )中的字符串。

如何使用Emacs lisp公式来自动计算出结果?

首先弄清楚想要的结果:

Col1 Col2 Col3 Col4 Col5
a a a b c d c d
a b
b a
c d

现在从第二行开始获取第一列的值。

可通过引用 @2$1 访问左上角单元格中的“a”。 可通过引用 @5$1 访问左下方单元格上的“c”。 然后可使用 @2$1..@5$1 访问单元格区间内值。

将上面获取的区间添加到 Col3 的第一个单元格中:

Col1 Col2 Col3 Col4 Col5
a a a a b c c d
a b
b a
c d

公式如下:

#+TBLFM: @2$3='(mapconcat 'identity (list @2$1..@5$1) " ")

公式要怎么解读呢?

解释时,区间 @2$1..@5$1 由单元格的值替换,并用空格分隔。 所以 (list @2$1..@5$1) 变成 (list "a" "a" "b" "c") ,整个公式变成

'(mapconcat 'identity (list "a" "a" "b" "c") " ")

上面的公式大体意味着的连接 ("a" "a" "b" "c") 中元素,并在每个元素之间添加一个空格。

把问题更一般话,我很可能不知道表包含多少行。 区间 @2$1..@5$1 变成 @2$1..@>$1 其中 @> 表示“最后一行”, @>$1 表示“第一列的最后一行”。

记住:我们希望第三列包含一个字符串,这个字符串由 Col1Col2 中的所有字符串去重后组成。 首先从 Col1Col2 列出所有值 (list =@2$1..@>$1 @2$2..@>$2) , 然后删除重复项 (delete-dups (list @2$1..@>$1 @2$2..@>$2)), 最后把这个表达式放在上面已有的表达式中。

#+TBLFM: @2$3='(mapconcat 'identity (delete-dups (list @2$1..@>$1 @2$2..@>$2)) " ")
Col1 Col2 Col3 Col4 Col5
a a a b c d c d
a b
b a
c d

好的。 现在你已经知道如何操纵区间,你可以用正确的公式替换 "?"了… 记住: Col4 包含仅在 Col1 中而不在 Col2 中的字符串,而 Col5 包含仅在 Col2 中而不在 Col1 中的字符串。 (注:可以编写自己的函数并在 Emacs lisp 公式中使用它们)

Col4Col5 的公式如下:

#+TBLFM: @2$4='(apply 'concat (delete-if (lambda(e) (member e (list @2$2..@>$2))) (list @2$1..@>$1)))
#+TBLFM: @2$5='(apply 'concat (delete-if (lambda(e) (member e (list @2$1..@>$1))) (list @2$2..@>$2)))

不要忘记,可以通过在表上的任何位置点击 C-c ' 来编辑表的公式: 它将打开公式编辑器,并突出显示光标所在的引用(在公式编辑器和表中)。 当需要检查引用是否正确时,公式编辑器非常方便。 此外,在该编辑器中的公式上点击 TAB 将格式化公式,这样更有助于公式编辑!

结论<a id="sec-"></a>

请浏览Org手册(精简但准确和最新)使用Lisp作为公式的信息:请参阅在线手册相关信息页

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容