Brantou的日常

二三事


  • 首页

  • 归档

  • 分类

  • 标签

  • 关于

  • 搜索

Org-mode表查找功能的简明教程

发表于 2017-04-09 | 分类于 org-mode |

原文Org tutorial on table lookup functions, 由 Jarmo Hurri 编辑,维护。本文只做学习之用。

序言

Org 提供三个不同的函数,用于在表中执行搜索和数据依赖的计算。 这些函数可以用于实现数组关联,统计匹配单元格,结果排名或分组数据。 以下示例将有助于开始使用这些功能。

<!– more –>

具有唯一键的关联数组

查找最直接的用法是将 Org 表的一部分视为关联数组:一个键可用于查找相应的值。

假设你去斯堪的纳维亚,并且想跟踪你花了多少钱在旅途中。 你决定将所有金额转换为欧元。 在行程之前,你请记下大致汇率,如下表所示:

 #+TBLNAME: rates
| currency        | abbreviation | euros |
|-----------------+--------------+-------|
| euro            | eur          |     1 |
| Norwegian krone | nok          |  0.14 |
| Swedish krona   | sek          |  0.12 |
| US dollar       | usd          |  0.77 |

接下来将使用函数 org-lookup-first 和前面的汇率表格来自动将不同货币的金额转换成欧元。 函数 org-lookup-first 的签名如下:

(org-lookup-first VAL S-LIST R-LIST &optional PREDICATE)

假定 PREDICATE 为 nil ,在这种情况下使用默认谓词(predicate) equal , 则该函数将在 S-LIST 中搜索 VAL 的第一个实例,并从 R-LIST 中的相应位置返回一个值。 在下表中,每笔金额分配了货币缩写; 对于相应的缩写,在汇率表格的第二列中进行查找,然后从第三列返回相应的汇率。 对于每一行只需要填充前四列; 第5列和第6列自动计算产生。 请注意,如果找不到键值,则会出现错误:在最后一行中,空键将被搜索。

|  date | expense          |  sum | currency |   rate |  euros |
|-------+------------------+------+----------+--------+--------|
|  1.3. | flights          |  324 | eur      |      1 |    324 |
|  4.6. | books and maps   |  243 | usd      |   0.77 | 187.11 |
| 30.7. | rental car       | 8300 | sek      |   0.12 |   996. |
|  2.7. | hotel            | 1150 | sek      |   0.12 |   138. |
|  2.7. | lunch            |  190 | sek      |   0.12 |   22.8 |
|  3.7. | fishing licenses | 1400 | nok      |   0.14 |   196. |
|  3.7. | gasoline         |  340 |          | #ERROR | #ERROR |
 #+TBLFM: $5='(org-lookup-first $4 '(remote(rates,@2$2..@>$2)) '(remote(rates,@2$3..@>$3)))::$6=$5*$3

多个匹配优先排序

教师的常见任务是从总分中分配考试成绩。 这种分级的起点是具有等级边界的表。 以下是一个这样的表,其中行按照特定等级所需的下限的递增排序。

 #+TBLNAME: grade-boundaries
| lower bound | grade |
|-------------+-------|
|           0 | F     |
|          10 | D     |
|          20 | C     |
|          30 | B     |
|          40 | A     |

使用函数 org-lookup-last 和根据前面的 等级边界 表来为学生分配成绩。 函数 org-lookup-last 的签名与 org-lookup-first 的完全相同:

(org-lookup-last VAL S-LIST R-LIST &optional PREDICATE)

函数 org-lookup-last 会搜索 S-LIST 中的最后一个匹配项,并从 R-LIST 中的相应位置返回一个值。 用于分配等级的查找思想如下:假定学生的考试成绩是33分。我们寻找学生的 marks 大于或等于下限的表中的最后一行; 在这种情况下,它是下边界的行30。学生的成绩是第二列的相应元素,在这种情况下是B.

因此,给定学生的标记数VAL,找到下限S满足 (>= VAL S) 的表等级边界的第一列的最后一行。 因此,我们将使用 >= 作为 PREDICATE 来执行匹配。 注意, VAL 和 S 按照它们在 org-lookup-last 的签名中的顺序被分配给谓词,其中 VAL 在 S-LIST 之前。 下表列出了从总 marks 到最终成绩的转换。 注: 文字插值 L 表示表值的字面值插入到Elisp公式中,这是必须的,因为一些值是数字,一些是符号。

| student | marks | grade |
|---------+-------+-------|
| X       |    30 | B     |
| Y       |    29 | C     |
| Z       |     5 | F     |
| W       |    55 | A     |
 #+TBLFM: $3='(org-lookup-last $2 '(remote(grade-boundaries,@2$1..@>$1)) '(remote(grade-boundaries,@2$2..@>$2)) '>=);L

统计匹配单元格

函数 org-lookup-all 不能在表等式中使用自己,因为它返回值列表。 但是,通过将函数与其他 elisp 函数相结合,可执行强大的查找任务。

作为一个简单的例子,计算表中缺少值的数量。 函数 org-lookup-all 的签名与其他两个查找函数的签名完全相同:

(org-lookup-all VAL S-LIST R-LIST &optional PREDICATE)

数搜索 S-LIST 中的所有匹配项,并从 R-LIST 中的相应位置返回所有相应的值。 与org-lookup-first和org-lookup-last的情况一样,如果 R-LIST 为nil,则直接返回 S-LIST 相应匹配值。 注意使用 E 标志来保留范围内的空字段。 还要注意,在这种情况下,以真正的二维范围来进行查找,这也是可能的

| group | round 1 | round 2 |
|-------+---------+---------|
| A     |         |     2.4 |
| B     |     4.7 |      11 |
| C     |         |         |
| D     |       5 |         |
| E     |         |     7.2 |
| F     |     3.2 |     4.3 |
| G     |         |     4.4 |
| H     |         |       8 |
|-------+---------+---------|
| total | missing |       7 |
 #+TBLFM: @>$3='(length(org-lookup-all "" '(@2$2..@-1$3) nil));E

排序结果

org-lookup-all 的另一个示例应用是结果的自动排序。 在下表中,总数越大越好。 请注意,Elisp表达式还自动处理关联关系。

| group | marks | rank |
|-------+-------+------|
| A     |    22 |    2 |
| B     |    22 |    2 |
| C     |    14 |    4 |
| D     |    28 |    1 |
| E     |     9 |    5 |
 #+TBLFM: $3='(+ 1 (length (org-lookup-all $2 '(@2$2..@>$2) nil '<)));N

统计原始数据的频率

数据分析中的常见情况是对可视化的原始数据值进行分类(分组)。 通常是通过统计在特定范围内的出现频率来完成的。 可使用函数 org-lookup-all ,结合其他 elisp 函数来执行此任务。 此示例还显示了如何使用表中的多个值构建更复杂的查找规则。

考虑下表,不同组A-I的不同结果。

 #+TBLNAME: raw-data
| group | result |
|-------+--------|
| A     |    2.3 |
| B     |    4.2 |
| C     |    1.1 |
| D     |    3.6 |
| E     |    4.5 |
| F     |    2.4 |
| G     |    1.0 |
| H     |    2.3 |
| I     |    2.8 |

将结果分为不同的,并且相斥的类。 例如,属于第一类的值在区间 [1,1.9] (包括端点)中。 为了执行这样的分类,我们定义了以下两参数谓词函数 in-interval 。 请注意,此函数的第一个参数是一对,其第一个元素是下限,第二个成员是该间隔的上限。

#+BEGIN_SRC emacs-lisp
  (defun in-interval (bounds el)
    (and (>= el (car bounds)) (<= el (cadr bounds))))
#+END_SRC
#+RESULTS:
: in-interval

使用这个谓词函数,我们可以构造一个具有分类边界和相应频率的表。 请注意,函数 org-lookup-all 的第一个参数是作为第一个参数传递给谓词 in-interval 中的第一个参数,是一对边界。

| lower bound | upper bound | frequency |
|-------------+-------------+-----------|
|           1 |         1.9 |         2 |
|           2 |         2.9 |         4 |
|           3 |         3.9 |         1 |
|           4 |         4.9 |         2 |
 #+TBLFM: $3='(length (org-lookup-all '($1 $2) '(remote(raw-data,@2$2..@>$2)) nil 'in-interval));N

结论

Org 的 lookup 函数可用于大量不同的数据相关计算。 例如,libreoffice或Excel用户熟悉的以下电子表格操作都可以使用它们来实现: HLOOKUP , VLOOKUP , COUNTIF , SUMIF 和 FREQUENCY 。

Last Updated 2017-05-23 Tue 13:28.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)

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

发表于 2017-04-08 | 分类于 org-mode |

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

序言

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

<!– more –>

示例 1: 操纵单元格

下面是一个简单的表格:

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

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

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

org-spreadsheet-table1.jpg

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

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

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

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

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

经过公式计算表格如下:

org-spreadsheet-table2.jpg

在执行公式时, $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-number 和 number-to-string 。)

解决方案 :不能使用 ;N 标志,因为它会强制将单元格解释为数字,如果这样做,将无法访问第一行单元格的值。 所以一个方案就是使用 string-to-number 和 number-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: 操纵行列区间

假设有以下表格

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

Col1 和 Col2 包含字符串。

第三列的第一个单元格包含一个字符串,这个字符串由 Col1 和 Col2 中的所有字符串去重后组成。 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 表示“第一列的最后一行”。

记住:我们希望第三列包含一个字符串,这个字符串由 Col1 和 Col2 中的所有字符串去重后组成。 首先从 Col1 和 Col2 列出所有值 (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 公式中使用它们)

Col4 和 Col5 的公式如下:

#+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 将格式化公式,这样更有助于公式编辑!

结论

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

Footnotes:

1

如果在Emacs中阅读本教程,请浏览手册的电子表格部分,点击链接:电子表格。

2

列公式适用于整个列,而单元格公式仅适用于当前单元格。 可以通过在字段中按 C-u C-c = 来插入单元格公式。

Last Updated 2017-05-23 Tue 13:28.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)

Org-mode的电子表格的简明教程

发表于 2017-04-06 | 分类于 org-mode |

原文Org as a spreadsheet system: a short introduction, 由 Bastien 编辑,维护。本文只做学习之用。

序言

这篇简短的教程将介绍使用 Org 作为电子表格系统需要的基础知识。

从一个非常简单的表开始:

student maths physics
bertrand 13 09
henri 15 14
arnold 17 13

上面的表格在 Org 文件中的样式:

| student  | maths | physics |
|----------+-------+---------|
| bertrand |    13 |      09 |
| henri    |    15 |      14 |
| arnold   |    17 |      13 |

本教程的目的是阐述如何从上面简单的表生成出如下所示的包含平均每个学生和每个学科的平均分的表:

student maths physics mean
bertrand 13 09 11
henri 15 14 14.5
arnold 17 13 15
means 15 12 13.5

<!– more –>

熟悉引用

先从每个学生的平均值开始。

| student  | maths | physics | mean      |
|----------+-------+---------+-----------|
| bertrand |    13 |      09 | [formula] |
| henri    |    15 |      14 |           |
| arnold   |    17 |      13 |           |

在往 [formula] 中插入公式之前,需要知道如何引用 ( refer )一行,一列或一个单元格。

了解引用的最简单的方法是当你在一个单元格时,键入 C-c ? 。

例如,如果在 [formula] 单元格中, C-c ? 展示给你的信息是: line @2, col $4, ref @2$4 or D2 , 这表示在第四列的第二行上,而这个字段的引用是 @2$4 或 D2 。

在任何时刻,如果不清楚行和列,可以随时使用 C-c } 打开引用的可视化网格: reference_visualization.jpg

第一个公式

将光标放在(空) [formula] 单元格中, 然后在此字段中输入 :=vmean($2..$3) 。 该公式意味着:计算此行中第二( $2 )到 第三( $3 )单元格的字段平均值。 如果喜欢其他符号,请输入 :=vmean(B&..C&) – 其中 & 字符代表在这一行。

在上面键入公式的行中,键入 C-c C-c , 你将观察到两点变化: 1) :=vmean($2..$3) 已被计算结果代替,2)以 #+TBLFM 开头的新行已被插入到表的底部。

#+TBLFM 行包含表的所有公式,在手动编辑时应小心。

列公式和单元格公式

经过上面的操作,表格变成了:

| student  | maths | physics | mean |
|----------+-------+---------+------|
| bertrand |    13 |      09 |   11 |
| henri    |    15 |      14 |      |
| arnold   |    17 |      13 |      |
#+tblfm: @2$4=vmean($2..$3)

但是我们真正想要的是计算“Mean”列中所有单元格的公式。 换句话说,我们真的想要一个列公式,而不是单元格公式。

要使用列公式替换当前公式,请返回到已定义的单元格,然后键入 =vmean($2..$3) 。 请注意,与之前插入的唯一区别在于公式以 = 替代前缀 := 。 完成后,在单元格中执行 C-c C-c :列公式替换先前公式,这正是我们想要的。

一旦执行了上面步骤,该单元格中的值应该与以前相同(即11),现在可以通过键入 C-u C-c * (或者在 #+TBLFM 行键入 C-c C-c ) 重新应用公式来更新此列中的所有单元格。

经过上面的步骤,表格如下所示:

| student  | maths | physics | mean |
|----------+-------+---------+------|
| bertrand |    13 |      09 |   11 |
| henri    |    15 |      14 | 14.5 |
| arnold   |    17 |      13 |   15 |
#+tblfm: $4=vmean($2..$3)

由于在 #+TBLFM 中的单个公式现在适用于整个列,所以它不包含任何对行的引用。 公式以前被应用于 @2$4 单元格,现在它被应用于 $4 列。

最后,为每个学科平均值添加一行。 此行包含两个字段公式,每个公式计算同一列中上面单元格的平均值:

| student  | maths | physics | mean |
|----------+-------+---------+------|
| bertrand |    13 |      09 |   11 |
| henri    |    15 |      14 | 14.5 |
| arnold   |    17 |      13 |   15 |
|----------+-------+---------+------|
| means    |    15 |      12 |      |
#+tblfm: $4=vmean($2..$3)::@5$2=vmean(@2$2..@4$2)::@5$3=vmean(@2$3..@4$3)

表格如下所示:

student maths physics mean
bertrand 13 09 11
henri 15 14 14.5
arnold 17 13 15
means 15 12  

交互的编辑公式

我们可通过将公式直接插入到表格单元格的方式来定义它们:在一个字段中键入 = 开始列公式的定义,和键入 := 开始一个单元格公式的定义。

如果你喜欢,可以在 minibuffer 中编辑公式:使用 C-c = 编辑列公式或 C-u C-c = 用于字段公式。

但是也可以通过键入 =C-c '= 在专用缓冲区中交互式地编辑公式。 此新缓冲区列出了表的所有公式,并提供编辑引用的功能。

当光标在引用上方时,表中的相应字段将突出显示。 很好! 但可以做的更多:可以使用 S-<left/right/up/down> 键实际选择引用。

formulas_editor.jpg

注:不用担心使用 M-<left/right> 左右移动列或 M-<up/down> 上下移动行会混淆 #+TBLFM 行中的引用,因为每次移动都会自动更新引用。

Calc和Elisp公式

公式的默认语法是 Calc ,用于进行计算的 GNU Emacs 包。

以下是Calc手册 中关于代数式公式的摘录:

Algebraic formulas use the operators `+', `-', `*', `/', and `^'. You
can use parentheses to make the order of evaluation clear. In the
absence of parentheses, `^' is evaluated first, then `*', then `/',
then finally `+' and `-'. For example, the expression

2 + 3*4*5 / 6*7^8 - 9

is equivalent to

2 + ((3*4*5) / (6*(7^8)) - 9

在 Org 表中,可使用引用而不是值来执行计算。

但是,如果需要使用 Emacs lisp 代码而不是 Calc ?

例如,将每个学生与Pi数字的十进制相关联,具体取决于他们在数学和物理学上的平均数。

为此,需要告诉 Org Pi数值的值。 可以通过添加以下行来实现:

#+CONSTANTS: pi=3.14159265358979323846

(不要忘了在 #+CONSTANTS 行上 键入 C-c C-c 以刷新 Local 设置)

你定义的 Emacs lisp 公式可能如下所示:

$5='(substring (number-to-string $pi) (round $4) (1+ (round $4)));N

Ahem. Let's parse this:

  • (substring S A B): 获取 S 字符串 A 和 B 之间的子串
  • (number-to-string $pi): 把常量"Pi"转换成字符串
  • (round $4): 获取 $4 四舍五入后整数值
  • ;N: 把当前单元格的值当成整数,而不是字符串

如果学生的平均数是10,该公式返回的Pi中第十位数字。

调试公式

现在表格如下所示:

Student Maths Physics Mean Pi number
Bertrand 13 09 11 5
Henri 15 14 14.5 7
Arnold 17 13 15 9

如果你回顾这个表,并试图了解 Emacs Lisp 函数具体完成了那些计算; 这个时候,你会产生疑惑,你可能会想要调试公式,并按步骤一步一步进行计算。

在表格的任意地方键入 C-c { 或 在一个单元格中键入 C-c C-c (或 C-u C-c * 在这个表的任何地方)都会打开表格公式调试器。 然后将一个一个地执行公式的计算,并在一个单独的缓冲区显示关于每个公式的计算步骤的细节。

Substitution history of formula
Orig:   '(substring (number-to-string $pi) (round $4) (1+ (round $4)));N
$xyz->  '(substring (number-to-string 3.14159265358979323846) (round $4) (1+ (round $4)))
@r$c->  '(substring (number-to-string 3.14159265358979323846) (round $4) (1+ (round $4)))
$1->    '(substring (number-to-string 3.14159265358979323846) (round 11) (1+ (round 11)))
Result: 5
Format: NONE
Final:  5

一旦调试完成,再次键入 C-c { 关闭调试器。

很多, 还有更多

使用 Org 作为电子表格系统非常容易上手。

本教程只是冰山一叫,你可以做的远不止于此! 可以使用相对引用,为公式的列和参数定义名称,定义自动重新计算的单元格等。还可以在公式中使用 Emacs lisp (请阅读本教程)。

浏览下 Org-mode手册 中的高级功能,它会给你一个更广阔的视角…

Last Updated 2017-06-01 Thu 13:40.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)

Babel: org-mode的元编程

发表于 2017-04-01 | 分类于 org-mode |

原文Babel: Introduction, 由 Eric Schulte , Dan Davison, Tom Dye 编辑,维护。本文只做学习之用。

1 序言

Bable 可让许多不同的语言工作一起。 编程语言生活在自然语言的 Org-mode 文档的代码块之中。 一个数据片段可从一个表格传递给一个 Pythoh 代码块,然后可能再转移到一个 R 代码块, 最终以数据块被嵌入段落的中间而终结,或者通过 gnuplot 代码块生成图片嵌入在文档中。

通过扩展 Org-mode, 使其具有编辑,导出和执行源代码的功能, Babel 将 Org-mode 变成了文学编程和可重复性研究的工具。

Babel 通过提供以下特性来增强 Org-mode对代码代码块的支持: Babel augments Org-mode support for code blocks by providing:

  • 代码块的交互和执行结果导出
  • 代码块可像函数一样可参数化,引用其他代码块,可被远程调用
  • 拼接,导出源代码到文件支持文学编程。

<!– more –>

2 概述

Babel 在几个不同的方面提供了新的功能,不同的人可能想在不同的地方开始。

在 Org-mode 中使用代码块
如果目前你还不知道怎么在 Org-mode 中创建代码块, 或者不清楚怎样在 Org-mode 的缓冲区和语言主模式编辑缓冲区(the language major-mode edit buffer)之间切换, 那么你需要应该看看Org 手册中的相关部分 和 下面的代码块章节, 尝试下,然后赶紧回来。
执行代码
Babel 的核心是能够在 Org-mode 代码块中执行代码, 从其他块和表格获取输入,并输出到更多的块和表。 从源代码执行开始描述。
Literate Programming
程序员编写的代码,通常以其他方式执行(例如从命令行或将其引入到交互式会话中), 那么对 Babel 的简单介绍就是将代码放在 Org-mode 文件的代码块中, 然后使用 Babel 的 Literate Programming 支持从 Org-mode 文件中扩展提取源代码。

所有这些用例以及 Babel 功能的详尽文档都被涵盖在 Org 手册的 使用源代码中。

3 初始配置

If you have a working Emacs installation, then getting started with Babel is a simple process.

  1. If you are running Emacs24 a current version of Org-mode with Babel is already available by default. Otherwise, it is strongly recommended that you update to the latest version of Org-mode by keeping current with Org-mode development. As of Org-mode 7.0, Babel is included as part of Org-mode.
  2. Optionally activate the subset of languages that you will want to execute with Babel. See Configure active languages instructions. Emacs Lisp is activated by default so this step can be skipped for now and all emacs-lisp examples will still work as expected.
  3. If you have made any changes don’t forget to evaluate your modified .emacs.

4 代码块

4.1 代码块在 Org-mode 中

Babel 是关于 Org-mode 中代码块的。 如果还不熟悉 Org-mode 中的代码块的概念,请在继续之前查看 Org-mode手册的相关章节。

受到支持语言的代码块可以出现在 Org-mode 文件的任意位置。 代码块可以直接在 Org-mode 文件中编辑,但通过 C-c '= 调用的函数 =org-edit-src-code 编辑代码往往更容易。 将代码块放全新的缓冲区中,同时激活相应语言的模式,语言的编辑特性你全都可用,真是爽。

#+begin_src language org-switches
,body
#+end_src

ruby 代码的代码块如下所示:

#+begin_src ruby
,require 'date'
,"This file was last evaluated on #{Date.today}"
#+end_src

4.2 代码块在 Babel 中

Babel 向代码块添加了一些新的元素。 基本结构变成了:

#+begin_src language  org-switches header-arguments
,body
#+end_src
language
代码块中代码的语言标示。 有效值必须是 org-babel-interpreters 的成员。
header-arguments
header-arguments 控制源代码块的执行和输出的许多方面。

请参阅Header Arguments部分,以查看可用的 header-arguments= 。

body
等待被执行的源代码。 一个重要的键绑定 C-c '= , 调用 =org-edit-src-code ,打开一个包含适合于该语言 major mode 的编辑缓冲区。

然后你就可以像往常在emacs编辑代码那样来编辑你的代码块。

5 源代码执行

Babel 通过将代码传递给解释器来执行解释语言(如shell,python,R等)的代码块。 在执行结果上可以做进一步的操作,如果你想的话。

5.1 示例

以下是三种不同语言的代码块,其后是其输出。 如果正在Emacs中查看本文档的 Org-mode 版本,则把光标放置在块的任何位置,然后按 C-c C-c 执行代码1(并随意更改它)。

5.1.1 Ruby

在 Org-mode 的文件中:

#+begin_src ruby
require 'date'
"This file was last evaluated on #{Date.today}"
#+end_src

HTML 导出的代码:

1
2
require 'date'
"This file was last evaluated on #{Date.today}"

HTML 导出的执行结果:

This file was last evaluated on 2017-04-05

5.1.2 Shell

在 Org-mode 的文件中:

#+begin_src sh
  echo "This file takes up `du -h babel-intro.org |sed 's/\([0-9k]*\)[ ]*babel-intro.org/\1/'`"
#+end_src

HTML 导出的代码:

echo "This file takes up `du -h babel-intro.org |sed 's/\([0-9k]*\)[ ]*babel-intro.org/\1/'`"

HTML 导出的执行结构:

This file takes up 36K

5.1.3 R

当前这个文件中最常用的词是? 在 Org-mode 文件中:

#+begin_src R :colnames yes
  words <- tolower(scan("babel-intro.org", what="", na.strings=c("|",":")))
  t(sort(table(words[nchar(words) > 3]), decreasing=TRUE)[1:10])
#+end_src

HTML 导出的代码:

1
2
words <- tolower(scan("babel-intro.org", what="", na.strings=c("|",":")))
t(sort(table(words[nchar(words) > 3]), decreasing=TRUE)[1:10])

5.1.4 ditaa

在 Org-mode 文件中:

#+begin_src ditaa :file blue.png :cmdline -r
+---------+
| cBLU    |
|         |
|    +----+
|    |cPNK|
|    |    |
+----+----+
#+end_src

HTML导出的代码:

+---------+
| cBLU    |
|         |
|    +----+
|    |cPNK|
|    |    |
+----+----+

HTML导出的结果图:

blue.png

5.1.5 js

console.log('Hello, world');

5.2 捕获代码执行结果

Babel 提供了两种根本不同的模式来捕获代码执行的结果: functional mode 和 scripting mode 。 模式的选择可以通过配置 :results 头参数来指定。

5.2.1 :results value (functional mode)

代码执行的结果是代码块中最后一个语句的值。 在 functional mode 下,代码块是具有返回值的函数。 一个代码块的返回值可以用作另一代码块的输入,即使是不同语言的输入。 这样的话,Babel成为一种元编程语言。 如果块返回表格数据(某种类型的向量,数组或表),那么将可以作为 Org-mode 的表格保存在缓冲区中。 functional mode 是默认设置。

作为示例,观察以下python代码块及其输出。

1
2
3
4
import time
print("Hello, today's date is %s" % time.ctime())
print("Two plus two is")
return 2 + 2

请注意,在 functional mode 下,输出只由最后一个语句返回,没有其他情况。

5.2.2 :results output (scripting mode)

在 scripting mode 中,Babel捕获代码块的文本输出并将其放置在 Org-mode 的缓冲区中。 它被称为 scripting mode ,因为代码块包含一系列命令,并返回每个命令的输出。 与功能模式不同,代码块本身除了其包含的命令的输出之外没有返回值。2

观察以下使用 scripting mode 执行代码块的结果。

1
2
3
4
import time
print("Hello, today's date is %s" % time.ctime())
print('Two plus two is')
2 + 2

在这里, scripting mode 返回了python写到 stdout 的文本。 因为代码块不包含最后一个语句 (2 + 2) 的 print() 语句,所以结果中不会出现4。

5.3 基于会话的代码块

对于某些语言,例如Python,R,ruby和shell,可以在Emacs中运行一个不完备的交互式会话进程。 这意味着创建了一个不同源代码块之间共享数据对象的持久化环境。 Babel 支持使用 :session 头参数来 指定代码块运行于特定会话中。 如果头参数被赋予一个值,那么该参数将被用作会话的名称。 因此,可以并发的在不同的会话中运行同一语言的不同代码块。

基于特定会话的代码块对于原型设计和调试特别有用。 函数 org-babel-pop-to-session 可用于切换会话缓冲区。

一旦代码块编辑完成,通常最好在会话之外执行它,因为这样它执行的环境将是确定的。

With R, the session will be under the control of Emacs Speaks Statistics as usual, and the full power of ESS is thus still available, both in the R session, and when switching to the R code edit buffer with ​C-c '​.

5.4 代码块的入参

Babel 支持代码块的参数化,即可以将参数传递给代码块,从而使它们函数化。 functional mode 和 scripting mode 都支持入参。

5.4.1 代码块作为函数的简单示例

首先我们来看一个非常简单的例子。 以下源代码块使用Python定义了一个函数,求入参的平方。

return x*x

在 Org-mode 文件中, 函数定义如下:

#+name: square
#+header: :var x=0
#+begin_src python
return x*x
#+end_src

调用函数如下:

#+call: square(x=6,y=8)

(对于 call 语法细节请参阅 Library of Babel)

nil
36

5.4.2 Org-mode 表格作为入参的更复杂的示例

在本例中,使用Emacs Lisp定义的一个名为 fibonacci-seq 的函数。 函数 fibonacci-seq 计算斐波纳契序列。 该函数只需要一个参数,在当前情况下参数即为 Org-mode 表格的引用。

下面即为传递给 fibonacci-seq 的 Org-mode 表格:

1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20

表格在 Org-mode 的缓冲区中如下所示:

#+tblname: fibonacci-inputs
| 1 | 2 | 3 | 4 |  5 |  6 |  7 |  8 |  9 | 10 |
| 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 |

Emacs Lisp的源代码:

1
2
3
4
5
6
(defun fibonacci (n)
(if (or (= n 0) (= n 1))
n
(+ (fibonacci (- n 1)) (fibonacci (- n 2)))))

(mapcar (lambda (row)
(mapcar #'fibonacci row)) fib-inputs)

在 Org-mode 中函数如下所示:

#+name: fibonacci-seq
#+begin_src emacs-lisp :var fib-inputs=fibonacci-inputs
  (defun fibonacci (n)
    (if (or (= n 0) (= n 1))
        n
      (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))

  (mapcar (lambda (row)
            (mapcar #'fibonacci row)) fib-inputs)
#+end_src

fibonacci-seq 的返回值,也是一个表格:

5.5 内联(In-line)的代码块

可使用以下语法内联(In-line)的执行代码:

Without header args: src_lang{code} or with header args: src_lang[args]{code},
for example src_python[:session]{10*x}, where x is a variable existing in the
python session.

代码如下:

src_python{return "Hello World!"}

执行结果:

5.6 代码块扩展

Babel 在执行之前“扩展”代码块,即,执行代码包括把引用的数据(或代码)填充到代码块内容里。 可以预览展开的内容,还可以在 tangling 期间展开代码。 扩展时,头参数和变量需要一并考虑进去。

preview
C-c M-b p (C-c C-v v) 关联到 org-babel-expand-src-block 函数。它可用于在代码块中预览扩展的内容, 对调试很有用。
tangling
扩展的的代码块可以被 tangled 。 tangling 可能包括的变量值
  • 其他代码的执行结果,
  • 存储在标题属性中变量,或者
  • 表格。

tangling 扩展代码块的一个可能用途是用于emacs初始化。 用户名和密码等值可以存储在标题属性或表格中。 可以使用 :no-expand 头参数来阻止 tangling 期间代码块的扩展。

下面是代码块及其生成的扩展的示例。

数据被存储在表格中:

username john-doe
password abc123

引用数据表格的代码块:

1
2
(setq my-special-username (first (first data)))
(setq my-special-password (first (second data)))

在代码块内部, C-c M-b p (C-c C-v v)扩展内容如下:

1
2
3
(let ((data (quote (("john-doe") ("abc123")))))
(setq my-special-username (first (first data)))
(setq my-special-password (first (second data))))

5.7 Org-mode 的元编程语言

因为用一种语言编写的函数的返回值可以被传递给另一种语言编写的函数, 或者传递到本身就可程序化的 Org-mode 的表格中, 所以可将 Babel 用作元功能编程语言。 Bable 可使许多语言一起工作, 混合使用各语言,每种语言可用于最合适的任务。

例如,在shell中进行一些系统诊断,并用R图形化诊断结果.

  1. 使用shell代码创建一个代码块,列出program目录中的目录以及它们的大小。Babel自动将输出转换为 Org-mode 表格。
    #+name: directories
    #+begin_src sh :results replace
      cd ~/program/ && du -sc * | grep -v total
    #+end_src
    

    代码如下:

    cd ~/program/ && du -sc * | grep -v total

    结果如下:

    #+RESULTS: directories
    |   2392 | github      |
    |  90728 | org         |
    |  15820 | program     |
    | 190488 | program.tgz |
    
  2. 一行R语言编写的函数将 Org-mode 表中的数据绘制为饼形图。 请注意,当前代码块如何使用前一代码块的 srcname 来获取的数据 。

    在 Org-mode 文件中:

    #+name: directory-pie-chart(dirs = directories)
    #+begin_src R :session R-pie-example :file ../images/babel/dirs.png :var dirs=directories() :results graphics
      pie(dirs[,1], labels = dirs[,2])
    #+end_src
    

    注: :results graphics 请参阅 Org Mode Features for R Source Code Blocks

    HTML 导出的代码:

    pie(dirs[,1],labels=dirs[,2])

    dirs.png

6 在Org表格中使用代码块

除了可将表格中的数据作为参数传递给代码块和结果存储为表格外, Babel 还有第三种方式使用 Org-mode 表格。 Org-mode 现有电子表格 功能允许使用 #+TBLFM 从指定单元格值自动计算出其他单元格值。 通过以上方式,表可使用calc 和 emacs lisp来执行计算任务。

Babel 有效扩展了 #+TBLFM 行使用代码块(以任何语言)进行必要计算的能力。

6.1 示例

6.1.1 示例 1: 使用R生成数据概要

将使用几个数字的平均值来填充 Org-mode 表中的一个单元格,来做简单示例。 首先,要生成数据, 以下代码块生成0和1之间的五个随机数来填充了 Org-mode 表。

在 Org-mode 文件中,如下所示:

#+name: tbl-example-data
#+begin_src R
runif(n=5, min=0, max=1)
#+end_src

HTML 导出的代码如下:

runif(n=5, min=0, max=1)

紧接着定义一个代码块计算来表列的平均值。

在 Org-mode 文件中,如下所示:

#+name: R-mean
#+begin_src R :var x=""
colMeans(x)
#+end_src

HTML 导出的代码如下:

colMeans(x)

最后,创建使用R代码的表。 通过使用 org-sbe (‘source block evaluate’)宏来完成的代码块的调用。

在 Org-mode 文件中,表格调用代码块如下所示:

#+tblname: summaries
|              mean |
|-------------------|
| 0.779619386699051 |
#+TBLFM: @2$1='(org-sbe "R-mean" (x "tbl-example-data()"))

HTML export of code:

mean
0.58

重新计算表格公式,请在表格中使用 C-u C-c C-c 。 每次重新计算表格公式时,代码块都会再次计算,因此计算的平均值会发生变化。

6.1.2 示例 2: Babel 的测试套件

While developing Babel, we used a suite of tests implemented as a large Org-mode table.

在开发 Babel 时,开发者曾使用了一个居大的 Org-mode 表作为测试套件。 要运行测试套件,我们只需使用 C-u C-c C-c 对表进行计算:运行所有测试,将结果与期望进行比较,并使用结果和通过/失败的状态信息来更新表。

测试套件的简单版本如下.

在 Org-mode 文件中,如下所示:

#+TBLNAME: org-babel-tests
| functionality    | block        | arg |    expected |     results | pass |
|------------------+--------------+-----+-------------+-------------+------|
| basic evaluation |              |     |             |             | pass |
|------------------+--------------+-----+-------------+-------------+------|
| emacs lisp       | basic-elisp  |   2 |           4 |           4 | pass |
| shell            | basic-shell  |     |           6 |           6 | pass |
| ruby             | basic-ruby   |     |   org-babel |   org-babel | pass |
| python           | basic-python |     | hello world | hello world | pass |
| R                | basic-R      |     |          13 |          13 | pass |
#+TBLFM: $5='(if (= (length $3) 1) (org-sbe $2 (n $3)) (org-sbe $2)) :: $6='(if (string= $4 $5) "pass" (format "expected %S but was %S" $4 $5))

HTML 导出的代码:

functionality block arg expected results pass
basic evaluation         pass
emacs lisp basic-elisp 2 4 4 pass
shell basic-shell   6 6 pass
ruby basic-ruby   org-babel org-babel pass
python basic-python   hello world hello world pass
R basic-R   13 13 pass
  1. 用于测试的代码块

    Org-mode 文件中,如下所示::

    #+name: basic-elisp
    #+begin_src emacs-lisp :var n=0
    (* 2 n)
    #+end_src
    

    HTML 导出代码,如下所示::

    (* 2 n)

    Org-mode 文件中,如下所示::

    #+name: basic-shell
    #+begin_src sh :results silent
    expr 1 + 5
    #+end_src
    

    HTML 导出代码,如下所示::

    expr 1 + 5

    Org-mode 文件中,如下所示::

    #+name: date-simple
    #+begin_src sh :results silent
    date
    #+end_src
    

    HTML 导出代码,如下所示::

    date

    Org-mode 文件中,如下所示::

    #+name: basic-ruby
    #+begin_src ruby :results silent
    "org-babel"
    #+end_src
    

    HTML 导出代码,如下所示::

    "org-babel"

    Org-mode 文件中,如下所示:

    #+name: basic-python
    #+begin_src python :results silent
    "hello world"
    #+end_src
    

    HTML 导出代码,如下所示::

    return "hello world"

    Org-mode 文件中,如下所示::

    #+name: basic-R
    #+begin_src R :results silent
    b <- 9
    b + 4
    #+end_src
    

    HTML 导出代码,如下所示::

    1
    2
    b <- 9
    b + 4

7 Babel库文件

(可参阅 Org manual:Library-of-Babel)

正如上面的 square 示例中看到的,一旦代码块被定义,可使用 lob 符号反复调用:

#+lob: square(x=6)

但是,若是需要为每个 Org-mode 缓冲区提供的通用,可重用的代码块呢?

除了当前的缓冲区外, Babel 还会搜索 *Babel*库文件中预先定义的代码块。 这是一个用户可扩展的现成的代码块集合,用于处理常见任务。 对于 Bable 库(尚未完成!)的一个可能的用途就是是使用R,gnuplot,asymptote等语言为 Org-mode 表中保存的数据提供绘图功能。 如果你定义的某些代码块 对其他 Org-mode 用户也非常有用,可考虑将其添加到 Babel 库中; 类似的,可以随时求助,*Babel* 可引用外部代码来解决问题 – 其他Babel用户也有机会提供一些有用的代码。

Babel预先填充(即把库中的代码块加载到缓冲区中)位于 Babel库文件 中的代码块 - library-of-babel.org 上的原始文件。 可使用 org-babel-lob-ingest (绑定到 C-c C-v i )从任何 Org-mode 文件中向库添加代码块。

(org-babel-lob-ingest "path/to/file.org")

注: 可以将表值或源代码块的输出传递给 Babel 库函数。 还可以在代码块的参数中引用 Babel 函数库函数。

8 文学化编程

Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.

让我们改改传统上构建程序的态度:不要认为程序的主要任务是指导计算机怎么做,相反,程序要致力于向人们解释,它想让计算机做什么。3

The practitioner of literate programming can be regarded as an essayist, whose main concern is with exposition and excellence of style. Such an author, with thesaurus in hand, chooses the names of variables carefully and explains what each variable means. He or she strives for a program that is comprehensible because its concepts have been introduced in an order that is best for human understanding, using a mixture of formal and informal methods that reinforce each other.

文学编程人士可被视为作家,他们首要考虑的任务是如何清楚地阐述、如何形成优秀的风格。 这样的作者胸有成竹,会仔细地挑选变量名,并给予解释。为力求程序之可读, 他/她使用形式和非形式互补的混合手法,将各种概念按照人们能理解的方式顺序编排下来。3 – Donald Knuth

Babel支持 文学编程 (LP),允许编程行为发生在 Org-mode 文档中。 然后可将 Org-mode 文件导出(用LP语言编写)到HTML或LaTeX等更可视化的文本格式中以供人类查阅和使用, 并且可以将嵌入的源代码( tangle in LP speak)转换成源代码文件以供计算机执行。

为了支持这些操作, Babel 依赖于 Org-mode 的 文档的导出功能 来编排文档, 依赖于使用 Noweb reference syntax tangling 代码文件的 org-babel-tangle ( C-c C-v t ) 函数。

以下示例演示了在 Babel 中 tangling 的过程。

8.1 tangling 的示例

8.1.1 简单文学编程示例 (Noweb syntax)

Tangling functionality is controlled by the tangle family of tangle header arguments. These arguments can be used to turn tangling on or off (the default), either for the code block or the Org-mode heading level.

以下代码块演示如何使用 org-babel-tangle ( C-c C-v t ) 把分散的代码块 tangle 为单个源代码文件。

以下两个代码块没有 tangle 头参数,因此不会创建源代码文件。 它们通过第三个代码块被包含在源代码文件中,该代码块具有 tangle 头参数。

Org-mode 文件中,如下所示::

#+name: hello-world-prefix
#+begin_src sh :exports none
  echo "/-----------------------------------------------------------\\"
#+end_src

Org-mode 文件中,如下所示:

#+name: hello-world-postfix
#+begin_src sh :exports none
  echo "\-----------------------------------------------------------/"
#+end_src

第三个代码块具有 tangle 头参数,指出将被写入的源代码的文件的名称。 它还包含了前面两个代码块的Noweb样式引用。 这些引用将在 tangling 期间扩展,以使它们包含在输出文件中。

Org-mode 文件中,如下所示::

#+name: hello-world
#+begin_src sh :tangle hello.sh :exports none :noweb yes
  <<hello-world-prefix>>
  echo "|                       hello world                         |"
  <<hello-world-postfix>>
#+end_src

调用函数 org-babel-tangle ( C-c C-v t )将shell源码写到 hello.sh 文件中:

1
2
3
4
#!/usr/bin/env sh
echo "/-----------------------------------------------------------\\"
echo "| hello world |"
echo "\-----------------------------------------------------------/"

此外,可以使用以下语法来插入代码块执行的结果,在下面情况下是名为 example-block 的代码块的执行结果。

#<< example-block() >>

任何可选参数都可以传递给 example-block() ,方法是将参数放入括号内,并遵循调用代码块函数定义的约定(参见 babel库)。 如下:

#<< example-block(a=9) >>

参数 “a” 的值设置为等于 “9”。 请注意,这些参数不在当前源代码块中执行,而是按字面顺序传递给 example-block() 。

8.1.2 用Bable初始化Emacs

dot-emacs.png

Babel 对于将Emacs初始化信息嵌入 Org-mode 文件中有特别的支持。 org-babel-load-file 函数可用于加载嵌入在 Org-mode 文件中的Emacs Lisp代码块,方法与加载常规Emacs Lisp文件(如.emacs)相同。

这就允许利用Org-mode的功能特性,例如折叠,标签,笔记,HTML导出等,来组织和维护Emacs初始化配置。

要想了解这一点,可以参考简单的优雅的Emacs初始化示例,或者查看 Org-babel-emacs-starter-kit 中提供的 Phil Hagelberg 的优秀 emacs-starter-kit 的 Babel Literate Programming 版本。 To try this out, either see the simple Literate Emacs Initialization example, or check out the Babel Literate Programming version of Phil Hagelberg’s excellent emacs-starter-kit available at Org-babel-emacs-starter-kit.

  1. 优雅的Emacs初始化

    请按照以下5个步骤进行操作:

    1. 在主目录的内创建一个名为 .emacs.d 的目录;
      mkdir ~/.emacs.d
    2. checkout 最新版本的 Org-mode 到这个新目录的src子目录中; of this new directory;
      1
      2
      3
      4
      cd ~/.emacs.d
      mkdir src
      cd src
      git clone git://orgmode.org/org-mode.git
    3. 将以下代码块放入Emacs初始化目录( ~/.emacs.d )下名为 init.el 的文件中。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      ;;; init.el --- Where all the magic begins
      ;;
      ;; This file loads Org-mode and then loads the rest of our Emacs initialization from Emacs lisp
      ;; embedded in literate Org-mode files.

      ;; Load up Org Mode and (now included) Org Babel for elisp embedded in Org Mode files
      (setq dotfiles-dir (file-name-directory (or (buffer-file-name) load-file-name)))

      (let* ((org-dir (expand-file-name
      "lisp" (expand-file-name
      "org" (expand-file-name
      "src" dotfiles-dir))
      )
      )

      (org-contrib-dir (expand-file-name
      "lisp" (expand-file-name
      "contrib" (expand-file-name
      ".." org-dir))
      )
      )

      (load-path (append (list org-dir org-contrib-dir)
      (or load-path nil)))
      )

      ;; load up Org-mode and Org-babel
      (require 'org-install)
      (require 'ob-tangle))


      ;; load up all literate org-mode files in this directory
      (mapc #'org-babel-load-file (directory-files dotfiles-dir t "\\.org$"))

      ;;; init.el ends here
    4. 在Emacs Lisp代码块中实现所有Emacs定制,嵌入在该目录中的 Org-mode 文件中; 和
    5. 重启Emacs读取自定义配置。

9 可重复性研究

An article about computational science in a scientific publication is not the scholarship itself, it is merely advertising of the scholarship. The actual scholarship is the complete software development environment and the complete set of instructions which generated the figures.

– D. Donoho

可重复性研究 (RR)是与科研出版物一起分发的所有数据,软件源代码和重现出版物中讨论的结果所需的工具的方法。 因此,RR包不仅描述了研究及其结果,而且成为可以复制和扩展研究的完整实验室。

Org-mode 已经很好的支持导出到HTML和LaTeX。 Babel 通过激活嵌入在 Org-mode 文档中的数据和代码块,使组织模式成为RR的工具; 整个文档变得可执行。 这使得鼓励读者重新创建结果并实验自己的思路来分发科研成果成为可能。

Sweave 是目前比较知名的RR工具,它提供了将R代码嵌入到LaTeX文档中的机制。 Sweave是一个成熟而且非常有用的工具,但我们认为 Babel 有几个优点:

  • 支持多种语言
  • 导出过程灵活强大,除了LaTeX之外,还包括HTML作为目标格式; 和
  • 文档可利用 Org-mode 强大的功能特性,支持项目规划和任务管理等。

Footnotes:

1

Calling C-c C-o on a code block will open the block’s results in a separate buffer.

2

This mode will be familiar to Sweave users.

3

摘自文艺编程 Literate Programming (原文中英文对照), 个人更喜欢文学编程。 literate-devOps

Last Updated 2017-10-31 Tue 21:54.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)

Leetcode编程练习

发表于 2017-03-21 | 分类于 技术积累 |

LeetCode 编程训练的积累,目前在努力做题中,日后整理!

<!– more –>

1 maxCount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
func maxCount(m int, n int, ops [][]int) int {
M := make([]([]int), 0,m)
for i := 0; i < m; i+=1 {
r := make([]int,n)
M = append(M, r)
}
var max int
var max_count int
for index, _ := range ops {
a, b := ops[index][0],ops[index][1]
fmt.Println(a,b)
rs := M[0:a]
for index, _ := range rs {
ris := rs[index]
for index, _ := range ris {
ri := ris[index]
if index == b {
break
}
ri +=1
ris[index]=ri
if ri > max {
max = ri
max_count = 0
}
if ri == max {
max_count +=1
}
}
rs[index] = ris
}
}
return max_count
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func maxCount(m int, n int, ops [][]int) int {
m_r, m_c := m, n
for _, op := range ops {
op_r := op[0]
op_c := op[1]
if op_r < m_r {
m_r = op_r
}
if op_c < m_c {
m_c = op_c
}
}
return m_r * m_c
}
1
2
3
func main() {
fmt.Println(maxCount(3,3, [][]int{[]int{2,2},[]int{3,3}}))
}

2 lengthOfLongestSubstring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func lengthOfLongestSubstring(s string) int {
byte_arr := []byte(s)
max_sub_arr := make([]byte, 0)
byte_sub_arr := make([]byte, 0)
byte_m := make(map[byte]int)
var start_index int
for index, byte_i := range byte_arr {
if ori_index, ok := byte_m[byte_i]; !ok {
byte_m[byte_i] = index
byte_sub_arr = append(byte_sub_arr, byte_i)
} else {
if len(max_sub_arr) < len(byte_sub_arr) {
max_sub_arr = byte_sub_arr
}
byte_sub_arr = byte_arr[ori_index+1 : index+1]
for ; start_index <= ori_index; start_index += 1 {
delete(byte_m, byte_arr[start_index])
}
byte_m[byte_i] = index
}
}
if len(max_sub_arr) < len(byte_sub_arr) {
max_sub_arr = byte_sub_arr
}
return len(max_sub_arr)
}
1
2
3
func main() {
fmt.Println(lengthOfLongestSubstring("abcabcbb"))
}

3 findMedianSortedArrays

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
total := len(nums1) + len(nums2)
if total%2 > 0 {
return findKth(nums1, nums2, total/2+1)
} else {
return (findKth(nums1, nums2, total/2) + findKth(nums1, nums2, total/2+1)) / float64(2)
}
}

func min(a, b int) int {
if a > b {
return b
} else {
return a
}
}

func findKth(a []int, b []int, k int ) float64 {
m, n := len(a), len(b)

//always assume that m is equal or smaller than n
if m > n {
return findKth(b, a, k)
}
if m == 0 {
return float64(b[k-1])
}

if k == 1 {
return float64(min(a[0], b[0]))
}

//divide k into two parts
pa := min(k/2, m)
pb := k - pa
if a[pa-1] < b[pb-1] {
return findKth(a[pa:], b, k-pa)
} else if a[pa-1] > b[pb-1] {
return findKth(a, b[pb:], k-pb)
} else {
return float64(a[pa-1])
}
}
1
2
3
4
5
6
func main() {
fmt.Println(findMedianSortedArrays([]int{1,3}, []int{2}))
fmt.Println(findMedianSortedArrays([]int{1,2}, []int{3, 4}))
fmt.Println(findMedianSortedArrays([]int{2,4,8}, []int{3,6,9}))
fmt.Println(findMedianSortedArrays([]int{2,4,7,8}, []int{3,5,6,9}))
}

4 findMin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
func findMin(nums []int) int {
if len(nums) < 1 {
return 0
}

if len(nums) == 1 {
return nums[0]
}

if len(nums) == 2 {
return min(nums[0], nums[1])
}

size := len(nums)
max_min_num := nums[0]
mid_num := nums[size/2]
if mid_num > max_min_num {
return findMin(nums[size/2+1:])
} else {
if nums[size/2-1] > nums[size/2] {
return nums[size/2]
} else {
return findMin(nums[:size/2])
}
}
}

func min(a, b int) int{
if a > b{
return b
} else {
return a
}
}

5 findDiagonalOrder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
func findDiagonalOrder(matrix [][]int) []int {
rst_arr := make([]int, 0)
if len(martix) < 1 || len(matrix[0]) < 1 {
return rst_arr
}
r_n := len(matrix)
c_n := len(matrix[0])
max_n := max(r_n, c_n)
order := "asc" // desc
var r_index, c_index int
for {
if r_index == r_n-1 && c_index == c_n-1 {
rst_arr = append(rst_arr, matrix[r_index][c_index])
break
}

switch order {
case "asc":
order = "desc"
for {
rst_arr = append(rst_arr, matrix[r_index][c_index])
if c_index == c_n-1 || r_index == 0 {
break
}
c_index += 1
r_index -= 1
}

if r_index == 0 {
if c_index == c_n-1 {
r_index += 1
} else {
c_index += 1
}
} else if c_index == c_n-1 {
r_index += 1
}
case "desc":
order = "asc"
for {
rst_arr = append(rst_arr, matrix[r_index][c_index])
if c_index == 0 || r_index == r_n-1 {
break
}
c_index -= 1
r_index += 1
}

if c_index == 0 {
if r_index == r_n-1 {
c_index += 1
} else {
r_index += 1
}
} else if r_index == r_n-1 {
c_index += 1
}
}
}
return rst_arr
}

6 thirdMax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
func parent(i int) int {
return i / 2
}

func left(i int) int {
return 2*i + 1
}

func right(i int) int {
return 2 * (i + 1)
}

func min_heapify(A []int, i int) {
l := left(i)
r := right(i)
var least int
if l < len(A) && A[l] < A[i] {
least = l
} else {
least = i
}
if r < len(A) && A[r] < A[least] {
least = r
}

if least != i {
A[i], A[least] = A[least], A[i]
min_heapify(A, least)
}
}

func thirdMax(nums []int) int {
var size int = 3
min_heap := make([]int, 0)
heap_M := make(map[int]bool)
var index int
for {
if !heap_M[nums[index]] {
heap_M[nums[index]] = true
min_heap = append(min_heap, nums[index])
}
index += 1
if len(min_heap) == size {
break
}
if index == len(nums) {
break
}
}

for i := len(min_heap) / 2; i >= 0; i -= 1 {
min_heapify(min_heap, i)
}

if index == len(nums) {
if len(min_heap) == size {
return min_heap[0]
} else {
var max int
for _, num := range min_heap {
if num > max {
max = num
}
}
return max
}
}

for i := index; i < len(nums); i += 1 {
num := nums[i]
if num > min_heap[0] && !heap_M[num] {
delete(heap_M, min_heap[0])
heap_M[num] = true
min_heap[0] = num
min_heapify(min_heap, 0)
}
}

return min_heap[0]
}
1
2
3
4
5
6
func main() {
fmt.Println(thirdMax([]int{3, 2, 1}))
fmt.Println(thirdMax([]int{1, 2}))
fmt.Println(thirdMax([]int{2, 2, 3, 1}))
fmt.Println(thirdMax([]int{5,2,4,1,3,6,0}))
}

7 combinationSum

7.1 combinationSum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
type PreCombin struct {
Sum int
Arr []int
}

func IsEqualCombin(lc, rc *PreCombin) bool {
if lc.Sum != rc.Sum {
return false
}

if len(lc.Arr) != len(rc.Arr) {
return false
}

for i := 0; i < len(lc.Arr); i += 1 {
l_num := lc.Arr[i]
r_num := rc.Arr[i]
if l_num != r_num {
return false
}
}
return true
}

func sortInsert(nums []int, num int) []int {
if len(nums) < 1 {
return []int{num}
}
new_nums := make([]int, len(nums)+1)
copy(new_nums, nums)
new_nums[len(nums)] = num

num_index := len(new_nums) - 1
for i := len(new_nums) - 2; i >= 0; i -= 1 {
if new_nums[i] <= new_nums[num_index] {
break
}
new_nums[i], new_nums[num_index] = new_nums[num_index], new_nums[i]
num_index = i
}
return new_nums
}

func combinationSum(candidates []int, target int) [][]int {
combin_arr := make([]([]int), 0)
pre_combin_arr := make([]*PreCombin, 0)
for index, _ := range candidates {
num := candidates[index]
if num > target {
continue
}

sub_pre_combin_arr := make([]*PreCombin, 0)
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if pre_combin.Sum == target {
continue
}

for {
if pre_combin.Sum+num <= target {
_pre_combin := &PreCombin{
Sum: pre_combin.Sum + num,
Arr: sortInsert(pre_combin.Arr, num),
}
sub_pre_combin_arr = append(sub_pre_combin_arr, _pre_combin)
pre_combin = _pre_combin
} else {
break
}
}
}

pre_combin := &PreCombin{
Sum: num,
Arr: []int{num},
}
sub_pre_combin_arr = append(sub_pre_combin_arr, pre_combin)
for {
if pre_combin.Sum+num <= target {
_pre_combin := &PreCombin{
Sum: pre_combin.Sum + num,
Arr: sortInsert(pre_combin.Arr, num),
}
sub_pre_combin_arr = append(sub_pre_combin_arr, _pre_combin)
pre_combin = _pre_combin
} else {
break
}
}

for index, _ := range sub_pre_combin_arr {
sub_pre_combin := sub_pre_combin_arr[index]
var hasEqual bool
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if IsEqualCombin(sub_pre_combin, pre_combin) {
hasEqual = true
break
}
}
if !hasEqual {
pre_combin_arr = append(pre_combin_arr, sub_pre_combin)
}
}
}

for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if pre_combin.Sum == target {
combin_arr = append(combin_arr, pre_combin.Arr)
}
}

return combin_arr
}
1
2
3
func main() {
fmt.Println(combinationSum([]int{2, 3, 6, 7}, 7))
}

7.2 combinationSum2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
type PreCombin struct {
Sum int
Arr []int
}

func IsEqualCombin(lc, rc *PreCombin) bool {
if lc.Sum != rc.Sum {
return false
}

if len(lc.Arr) != len(rc.Arr) {
return false
}

for i := 0; i < len(lc.Arr); i += 1 {
l_num := lc.Arr[i]
r_num := rc.Arr[i]
if l_num != r_num {
return false
}
}
return true
}

func sortInsert(nums []int, num int) []int {
if len(nums) < 1 {
return []int{num}
}
new_nums := make([]int, len(nums)+1)
copy(new_nums, nums)
new_nums[len(nums)] = num

num_index := len(new_nums) - 1
for i := len(new_nums) - 2; i >= 0; i -= 1 {
if new_nums[i] <= new_nums[num_index] {
break
}
new_nums[i], new_nums[num_index] = new_nums[num_index], new_nums[i]
num_index = i
}
return new_nums
}

func combinationSum2(candidates []int, target int) [][]int {
combin_arr := make([]([]int), 0)
pre_combin_arr := make([]*PreCombin, 0)
for index, _ := range candidates {
num := candidates[index]
if num > target {
continue
}

sub_pre_combin_arr := make([]*PreCombin, 0)
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if pre_combin.Sum == target {
continue
}
if pre_combin.Sum+num <= target {
_pre_combin := &PreCombin{
Sum: pre_combin.Sum + num,
Arr: sortInsert(pre_combin.Arr, num),
}
sub_pre_combin_arr = append(sub_pre_combin_arr, _pre_combin)
}
}

pre_combin := &PreCombin{
Sum: num,
Arr: []int{num},
}
sub_pre_combin_arr = append(sub_pre_combin_arr, pre_combin)

for index, _ := range sub_pre_combin_arr {
sub_pre_combin := sub_pre_combin_arr[index]
var hasEqual bool
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if IsEqualCombin(sub_pre_combin, pre_combin) {
hasEqual = true
break
}
}
if !hasEqual {
pre_combin_arr = append(pre_combin_arr, sub_pre_combin)
}
}
}

for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if pre_combin.Sum == target {
combin_arr = append(combin_arr, pre_combin.Arr)
}
}

return combin_arr
}
1
2
3
4
5
func main() {
fmt.Println(combinationSum2([]int{10, 1, 2, 7, 6, 1, 5}, 8))
fmt.Println(combinationSum2([]int{4,4,2,1,4,2,2,1,3}, 6))
fmt.Println(combinationSum2([]int{3,1,3,5,1,1}, 8))
}

7.3 combinationSum3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
type PreCombin struct {
Sum int
Arr []int
}

func IsEqualCombin(lc, rc *PreCombin) bool {
if lc.Sum != rc.Sum {
return false
}

if len(lc.Arr) != len(rc.Arr) {
return false
}

for i := 0; i < len(lc.Arr); i += 1 {
l_num := lc.Arr[i]
r_num := rc.Arr[i]
if l_num != r_num {
return false
}
}
return true
}

func sortInsert(nums []int, num int) []int {
if len(nums) < 1 {
return []int{num}
}
new_nums := make([]int, len(nums)+1)
copy(new_nums, nums)
new_nums[len(nums)] = num

num_index := len(new_nums) - 1
for i := len(new_nums) - 2; i >= 0; i -= 1 {
if new_nums[i] <= new_nums[num_index] {
break
}
new_nums[i], new_nums[num_index] = new_nums[num_index], new_nums[i]
num_index = i
}
return new_nums
}

func combinationSum3(k int, n int) [][]int {
candidates := make([]int, 9)
for index, _ := range candidates {
candidates[index] = index + 1
}
target := n

combin_arr := make([]([]int), 0)
pre_combin_arr := make([]*PreCombin, 0)
for index, _ := range candidates {
num := candidates[index]
if num > target {
continue
}

sub_pre_combin_arr := make([]*PreCombin, 0)
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if pre_combin.Sum == target {
continue
}
if pre_combin.Sum+num <= target {
_pre_combin := &PreCombin{
Sum: pre_combin.Sum + num,
Arr: sortInsert(pre_combin.Arr, num),
}
sub_pre_combin_arr = append(sub_pre_combin_arr, _pre_combin)
}
}

pre_combin := &PreCombin{
Sum: num,
Arr: []int{num},
}
sub_pre_combin_arr = append(sub_pre_combin_arr, pre_combin)

for index, _ := range sub_pre_combin_arr {
sub_pre_combin := sub_pre_combin_arr[index]
var hasEqual bool
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if IsEqualCombin(sub_pre_combin, pre_combin) {
hasEqual = true
break
}
}
if !hasEqual {
pre_combin_arr = append(pre_combin_arr, sub_pre_combin)
}
}
}


for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if pre_combin.Sum == target && len(pre_combin.Arr) == k {
combin_arr = append(combin_arr, pre_combin.Arr)
}
}

return combin_arr
}
1
2
3
4
func main() {
fmt.Println(combinationSum3(3, 7))
fmt.Println(combinationSum3(3, 9))
}

7.4 combinationSum4

7.4.1 V1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
type PreCombin struct {
Sum int
Arr []int
}

func IsEqualCombin(lc, rc *PreCombin) bool {
if lc.Sum != rc.Sum {
return false
}

if len(lc.Arr) != len(rc.Arr) {
return false
}

for i := 0; i < len(lc.Arr); i += 1 {
l_num := lc.Arr[i]
r_num := rc.Arr[i]
if l_num != r_num {
return false
}
}
return true
}

func sortInsert(nums []int, num int) []int {
if len(nums) < 1 {
return []int{num}
}
new_nums := make([]int, len(nums)+1)
copy(new_nums, nums)
new_nums[len(nums)] = num

num_index := len(new_nums) - 1
for i := len(new_nums) - 2; i >= 0; i -= 1 {
if new_nums[i] <= new_nums[num_index] {
break
}
new_nums[i], new_nums[num_index] = new_nums[num_index], new_nums[i]
num_index = i
}
return new_nums
}

func permut_num(nums []int) int {
size := len(nums)
num_M := make(map[int]int)
for _, num := range nums {
num_M[num] += 1
}

if len(num_M) == 1 {
return 1
}

var max_count int
var max_count_num int
for num, count := range num_M {
if count > max_count {
max_count = count
max_count_num = num
}
}
delete(num_M, max_count_num)

var factor int = 1
for i := size; i > max_count; i -= 1 {
factor *= i
}

var un_factor int = 1
for _, count := range num_M {
for i := count; i > 0; i -= 1 {
un_factor *= i
}
}

return factor / un_factor
}

func combinationSum4(nums []int, target int) int {
pre_combin_arr := make([]*PreCombin, 0)
for index, _ := range nums {
num := nums[index]
if num > target {
continue
}

sub_pre_combin_arr := make([]*PreCombin, 0)
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if pre_combin.Sum == target {
continue
}

for {
if pre_combin.Sum+num <= target {
_pre_combin := &PreCombin{
Sum: pre_combin.Sum + num,
Arr: sortInsert(pre_combin.Arr, num),
}
sub_pre_combin_arr = append(sub_pre_combin_arr, _pre_combin)
pre_combin = _pre_combin
} else {
break
}
}
}

pre_combin := &PreCombin{
Sum: num,
Arr: []int{num},
}
sub_pre_combin_arr = append(sub_pre_combin_arr, pre_combin)
for {
if pre_combin.Sum+num <= target {
_pre_combin := &PreCombin{
Sum: pre_combin.Sum + num,
Arr: sortInsert(pre_combin.Arr, num),
}
sub_pre_combin_arr = append(sub_pre_combin_arr, _pre_combin)
pre_combin = _pre_combin
} else {
break
}
}

for index, _ := range sub_pre_combin_arr {
sub_pre_combin := sub_pre_combin_arr[index]
var hasEqual bool
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if IsEqualCombin(sub_pre_combin, pre_combin) {
hasEqual = true
break
}
}
if !hasEqual {
pre_combin_arr = append(pre_combin_arr, sub_pre_combin)
}
}
}

var permuts int
for index, _ := range pre_combin_arr {
pre_combin := pre_combin_arr[index]
if pre_combin.Sum == target {
permuts += permut_num(pre_combin.Arr)
}
}

return permuts
}

7.4.2 V2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
func permut_num(num_M map[int]int) int {
if len(num_M) == 1 {
return 1
}

var sum_count int
var max_count int
var max_count_num int
for num, count := range num_M {
sum_count += count
if count > max_count {
max_count = count
max_count_num = num
}
}
delete(num_M, max_count_num)

var factor int = 1
for i := sum_count; i > max_count; i -= 1 {
factor *= i
}

var un_factor int = 1
for _, count := range num_M {
for i := count; i > 0; i -= 1 {
un_factor *= i
}
}

return factor / un_factor
}

func combinationSum4(nums []int, target int) int {
var result_num int
if len(nums) == 0 {
return 0
}

if len(nums) == 1 {
if target%nums[0] == 0 {
return 1
} else {
return 0
}
}

fir_num := nums[0]
var factor int = 0
for sub_sum := 0; sub_sum <= target; sub_sum += fir_num {
combin_M_arr := sub_combin(nums[1:], target-fir_num*factor)
if len(combin_M_arr) > 0 {
for index, _ := range combin_M_arr {
combin_M := combin_M_arr[index]
combin_M[fir_num] = factor
result_num += permut_num(combin_M)
}
}
if fir_num*factor == target {
result_num += 1
}
factor += 1
}

return result_num
}

func sub_combin(nums []int, target int) [](map[int]int) {
if target < 1 {
return []map[int]int{}
}

if len(nums) == 1 {
if target%nums[0] == 0 {
return []map[int]int{
map[int]int{
nums[0]: target / nums[0],
},
}
} else {
return []map[int]int{}
}
}

fir_num := nums[0]
var factor int = 0
combin_M_arr := make([]map[int]int, 0)
for sub_sum := 0; sub_sum <= target; sub_sum += fir_num {
sub_combin_M_arr := sub_combin(nums[1:], target-fir_num*factor)
if len(sub_combin_M_arr) > 0 {
for index, _ := range sub_combin_M_arr {
combin_M := sub_combin_M_arr[index]
combin_M[fir_num] = factor
combin_M_arr = append(combin_M_arr, combin_M)
}
}

if fir_num*factor == target {
combin_M := map[int]int{
fir_num: factor,
}
combin_M_arr = append(combin_M_arr, combin_M)
}

factor += 1
}

return combin_M_arr
}
1
2
3
4
5
func main() {
fmt.Println(combinationSum4([]int{1,2,3}, 4))
fmt.Println(combinationSum4([]int{1,50}, 200))
fmt.Println(combinationSum4([]int{3,33,333}, 10000))
}

7.4.3 V3

动态规划解法

  • dp[i] += dp[i-num]
  • dp[i+num] += dp[i]
1
2
3
4
5
6
7
8
9
10
11
12
func combinationSum4(nums []int, target int) int {
dp := make([]int, target+1)
dp[0] = 1
for i := 1; i <= target; i += 1 {
for _, num := range nums {
if i >= num {
dp[i] += dp[i-num]
}
}
}
return dp[target]
}
1
2
3
4
5
func main() {
fmt.Println(combinationSum4([]int{1,2,3}, 4))
fmt.Println(combinationSum4([]int{1,50}, 200))
fmt.Println(combinationSum4([]int{3,33,333}, 10000))
}

8 combine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func combine(n int, k int) [][]int {
return subCombine(1, n, k)
}

func subCombine(start, end, k int) [][]int {
if k < 1 || end-start+1 < k {
return [][]int{}
}

combine_arr := make([][]int, 0)
if k == 1 {
for i := start; i <= end; i += 1 {
combine_arr = append(combine_arr, []int{i})
}
}

for i := start; i <= end-(k-1); i += 1 {
sub_combine_arr := subCombine(i+1, end, k-1)
if len(sub_combine_arr) > 0 {
for index, _ := range sub_combine_arr {
combines := append([]int{i}, sub_combine_arr[index]...)
combine_arr = append(combine_arr, combines)
}
}
}

return combine_arr
}
1
2
3
func main() {
fmt.Println(combine(4,2))
}

9 pathSum

9.1 hasPathSum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}

func hasPathSum(root *TreeNode, sum int) bool {
if root == nil {
return false
}

if root.Left == nil && root.Right == nil {
if root.Val == sum {
return true
} else {
return false
}
}

return hasPathSum(root.Left, sum-root.Val) || hasPathSum(root.Right, sum-root.Val)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func main() {
lc := &TreeNode{
Val: 4,
Left: &TreeNode{
Val: 11,
Left: &TreeNode{
Val: 7,
},
Right: &TreeNode{
Val: 2,
},
},
}
rc := &TreeNode{
Val: 8,
Left: &TreeNode{
Val: 13,
},
Right: &TreeNode{
Val: 4,
Left: &TreeNode{
Val: 5,
},
Right: &TreeNode{
Val: 1,
},
},
}
root := &TreeNode{
Val: 5,
Left: lc,
Right: rc,
}

fmt.Println(hasPathSum(root, 22))
}

9.2 pathSum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}

func pathSum(root *TreeNode, sum int) [][]int {
if root == nil {
return [][]int{}
}

if root.Left == nil && root.Right == nil {
if root.Val == sum {
return [][]int{[]int{root.Val}}
} else {
return [][]int{}
}
}

var lc_path_arr, rc_path_arr [][]int
if root.Left != nil {
lc_path_arr = pathSum(root.Left, sum-root.Val)
}

if root.Right != nil {
rc_path_arr = pathSum(root.Right, sum-root.Val)
}

path_arr := make([][]int, 0)
if len(lc_path_arr) > 0 {
for index, _ := range lc_path_arr {
path := lc_path_arr[index]
path = append([]int{root.Val}, path...)
path_arr = append(path_arr, path)
}
}

if len(rc_path_arr) > 0 {
for index, _ := range rc_path_arr {
path := rc_path_arr[index]
path = append([]int{root.Val}, path...)
path_arr = append(path_arr, path)
}
}

return path_arr
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func main() {
lc := &TreeNode{
Val: 4,
Left: &TreeNode{
Val: 11,
Left: &TreeNode{
Val: 7,
},
Right: &TreeNode{
Val: 2,
},
},
}
rc := &TreeNode{
Val: 8,
Left: &TreeNode{
Val: 13,
},
Right: &TreeNode{
Val: 4,
Left: &TreeNode{
Val: 5,
},
Right: &TreeNode{
Val: 1,
},
},
}
root := &TreeNode{
Val: 5,
Left: lc,
Right: rc,
}

fmt.Println(pathSum(root, 22))
}

9.3 number of path

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}

func pathSum(root *TreeNode, sum int) int {
if root == nil {
return 0
}

return sumUp(root, 0, sum) + pathSum(root.Left, sum) + pathSum(root.Right, sum)
}

func sumUp(node *TreeNode, pre, sum int) int {
if node == nil {
return 0
}

var cur int = pre + node.Val
var res_num int
if cur == sum {
res_num += 1
}
return res_num + sumUp(node.Left, cur, sum) + sumUp(node.Right, cur, sum)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
func main() {
lc := &TreeNode{
Val: 5,
Left: &TreeNode{
Val: 3,
Left: &TreeNode{
Val: 3,
},
Right: &TreeNode{
Val: -2,
},
},
Right: &TreeNode{
Val: 2,
Right: &TreeNode{
Val: 1,
},
},
}
rc := &TreeNode{
Val: -3,
Right: &TreeNode{
Val: 11,
},
}
root := &TreeNode{
Val: 10,
Left: lc,
Right: rc,
}

fmt.Println(pathSum(root, 8))
}

9.4 min path sum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
func minPathSum(grid [][]int) int {
dp := make([][]int, len(grid))
for index, _ := range dp {
dp[index] = make([]int, len(grid[0]))
}

for r_i, _ := range grid {
for c_i, _ := range grid[r_i] {
if r_i == 0 {
if c_i > 0 {
dp[r_i][c_i] = grid[r_i][c_i] + dp[r_i][c_i-1]
} else {
dp[r_i][c_i] = grid[r_i][c_i]
}
continue
}
if c_i == 0 {
dp[r_i][0] = grid[r_i][0] + dp[r_i-1][0]
continue
}

dp[r_i][c_i] = grid[r_i][c_i] + min(dp[r_i-1][c_i], dp[r_i][c_i-1])
}
}

return dp[len(dp)-1][len(dp[0])-1]
}

func min(a, b int) int {
if a > b {
return b
} else {
return a
}
}
1
2
3
4
5
6
7
func main() {
fmt.Println(minPathSum([][]int{
[]int{1, 3, 1},
[]int{1, 5, 1},
[]int{4, 2, 1},
}))
}

9.5 binary-tree maximum path sum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}

type BpNode struct {
MaxSum_c int
MaxSum_b int
Val int
Left *BpNode
Right *BpNode
}

func copyTree2Bp(root *TreeNode) *BpNode {
if root == nil {
return nil
}

return &BpNode{
Val: root.Val,
Left: copyTree2Bp(root.Left),
Right: copyTree2Bp(root.Right),
}
}

func max(a, b int) int {
if a < b {
return b
} else {
return a
}
}

func bpMaxSum(bpr *BpNode) int {
if bpr == nil {
return 0
}

max_n := max(bpr.MaxSum_c, bpr.MaxSum_b)
if bpr.Left != nil {
max_n = max(max_n, bpMaxSum(bpr.Left))
}
if bpr.Right != nil {
max_n = max(max_n, bpMaxSum(bpr.Right))
}

return max_n
}

func maxPathSum(root *TreeNode) int {
bpr := copyTree2Bp(root)
maxPathSumHelper(bpr)
return bpMaxSum(bpr)
}

func maxPathSumHelper(bpr *BpNode) (
max_sum_b int,
) {
if bpr == nil {
return 0
}

lmax_sum_b := maxPathSumHelper(bpr.Left)
rmax_sum_b := maxPathSumHelper(bpr.Right)

bpr.MaxSum_c = bpr.Val + max(0, lmax_sum_b) + max(0, rmax_sum_b)
bpr.MaxSum_b = bpr.Val + max(0, max(lmax_sum_b, rmax_sum_b))

return bpr.MaxSum_b
}
1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
root := &TreeNode{
Val: 1,
Left: &TreeNode{
Val: 2,
},
Right: &TreeNode{
Val: 3,
},
}

fmt.Println(maxPathSum(root))
}

9.6 sum root to leaf numbers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}

func sumNumbers(root *TreeNode) int {
path_arr := collectPath(root)

var sum int
for index, _ := range path_arr {
path := path_arr[index]
var sub_sum int
for _, num := range path {
sub_sum = num + sub_sum*10
}
sum += sub_sum
}

return sum
}

func collectPath(root *TreeNode) [][]int {
if root == nil {
return [][]int{}
}

if root.Left == nil && root.Right == nil {
return [][]int{
[]int{root.Val},
}
}

lpath_arr := collectPath(root.Left)
rpath_arr := collectPath(root.Right)
lpath_arr = append(lpath_arr, rpath_arr...)
for index, _ := range lpath_arr {
path := lpath_arr[index]
path = append([]int{root.Val}, path...)
lpath_arr[index] = path
}
return lpath_arr
}
1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
root := &TreeNode{
Val: 1,
Left: &TreeNode{
Val: 2,
},
Right: &TreeNode{
Val: 3,
},
}

fmt.Println(sumNumbers(root))
}

10 poor pigs

1
2
3
4
5
6
7
8
9
10
11
12
13
func poorPigs(buckets int, minutesToDie int, minutesToTest int) int {
time := minutesToTest/minutesToDie + 1
res := 0
for {
if int(math.Pow(float64(time), float64(res))) < buckets {
res = res + 1
} else {
break
}
}

return res
}
Last Updated 2018-04-25 Wed 22:16.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)

Go的日志库logrus试用

发表于 2017-03-21 | 分类于 org-mode |

1 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import (
"os"

log "github.com/sirupsen/logrus"
)

func init() {
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})

// Output to stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)

// Only log the warning severity or above.
log.SetLevel(log.WarnLevel)
}

func main() {
log.WithFields(log.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")

log.WithFields(log.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")

log.WithFields(log.Fields{
"omg": true,
"number": 100,
}).Fatal("The ice breaks!")

// A common pattern is to re-use fields between logging statements by re-using
// the logrus.Entry returned from WithFields()
contextLogger := log.WithFields(log.Fields{
"common": "this is a common field",
"other": "I also should be logged always",
})

contextLogger.Info("I'll be logged with common and other field")
contextLogger.Info("Me too")
}
Last Updated 2017-06-19 Mon 23:25.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)

Org-mode手册

发表于 2017-03-21 | 分类于 org-mode |

org-mode我用了两年,却未曾深入。 最近两周静下心来,仔仔细细的钻研了一番,深深被这厮震撼到了,作为文档编辑工作,在我的认知范围里,无出其右。 归纳整理于此,以作留存,馈与日后。

<!– more –>

1 文档结构

1.1 标题

Org 是在大纲模式之上实现的。 大纲模式可以让我们用层次结构来组织文档,这(至少对我来说)是笔记和想法的最好实现方式。 这种结构可以折叠(隐藏)文档的一部分而只显示文档的大概结构或者只显示我们正在处理的部分。 Org 大大简化了大纲模式的使用,它把大纲模式的整个显示/隐藏功能整合到了一个命令中:org-cycle,这个命令绑定到了TAB键上。

标题定义了大纲树的结构,以处于一行左边缘的一个或多个星号开头,如下:

* Top level headline
** Second level
*** 3rd level
     some text
** 3rd level
     more text
, Another top level headline

1.1.1 视图命令

Table 1: 视图命令
Key Desc Command
TAB 子树循环,在下列状态之间转换当前子树: _,->folded->children->subtree–._ org-cycle
S-TAB 全局循环, 在下列状态之间转换当前的整个buffer: _,->overview->contents->show all–._ org-global-cycle
C-c C-r 显示当前位置的上下文,展示当前条目,紧跟的标题和标题的层次结构。 适用于通过稀疏树命令或议程命令展露出来的位置附近工作。 org-reveal
C-c C-k 展开子树的所有标题,CONTENT视图只有一个子树。 outline-show-branches
C-c TAB 展开子树的所有直接子节点。 outline-show-children
C-c C-x b 在间接缓冲区中显示当前子树 org-tree-to-indirect-buffer
C-c C-x v 将区域中的可见文字复制到 kill ring. org-copy-visible

org-mode默认的视图模式是'OVERVIEW',即概览模式,只有顶层的标题可见。 你可以通过配置变量 org-startup-folded 来改变视图模式,如下:

1
2
(setq org-startup-folded 'content)
(setq org-catch-invisible-edits nil) ;; prevent editing an invisible part of the bu↵er

当然你也可以为每个文件指定视图模式,只要在文件buffer中任意位置包含以下语句(推荐配置在文件头):

#+STARTUP: overview
#+STARTUP: content
#+STARTUP: showall
#+STARTUP: showeverything

更进一步,任何条目都包含 VISIBILITY 属性,此属性定义了条目的视图模式,覆盖一般性设置。可接受的值为: folded children content all, 示例如下

#+STARTUP: overview
* A
:PROPERTIES:
:VISIBILITY: all
:END:

1.1.2 跳转命令

Table 2: 标题跳转命令
Key Desc Command
C-c C-n 跳转到下一个标题 org-next-visible-heading
C-c C-p 跳转到上一个标题 org-previous-visible-heading
C-c C-f 跳转到下一个同级标题 org-forward-same-level
C-c C-b 跳转到上一个同级标题 org-backward-same-level
C-c C-u 跳回更高一级的标题 outline-up-heading
C-c C-j 跳转到别处,不改变当前的视图模式,创建一个临时buffer来展示当前文档 org-goto

在 C-c C-j 触发的临时buffer中,可用的命令如下:

TAB      Cycle visibility.
down/up  Next/previous visible headline.
RET      Select this location.
/        Do a Sparse-tree search

若是关闭了 org-goto-auto-isearch ,以下命令可用:

n/p      Next/previous visible headline.
f/b      Next/previous headline same level.
u        One level up.
0-9      数字参数
q        退出

1.1.3 编辑命令

Table 3: 编辑命令
Key Desc Command
M-RET 插入一个同级标题在当前位置(行首,把当前行转成标题;行中,截断余下文本,在下一行生成标题) org-insert-heading
M-S-RET 在M-RET的基础上,添加了 TODO 标示 org-insert-todo-heading
C-RET 在当前子树的结束位置插入同级标题 org-insert-heading-respect-content
C-S-RET 在CRET的基础上,添加了 TODO 标示 org-insert-todo-heading-respect-content
TAB 用于还未输入文本信息的标题,第一个TAB变为之前标题的子标题,第二个TAB变为父标题,第三个TAB恢复原有等级 (,->children->parent->initial)) org-cycle
M-left 当前标题提升一个等级 org-do-promote
M-right 当前标题降低一个等级 org-do-demote
M-S-left 当前整个子树提升一个等级 org-promote-subtree
M-S-right 当前整个子树降低一个等级 org-demote-subtree
M-up 当前整个子树和前面同级子树交换位置 org-move-subtree-up
M-down 当前整个子树和后面同级子树交换位置 org-move-subtree-down
M-h Mark the element at point. org-mark-element
C-c @ Mark the subtree at point. 目前看起来是可视化选中当前子树 org-mark-subtree
C-c C-x C-w 剪切子树到 kill ring org-cut-subtree
C-c C-x M-w 拷贝子树到 kill ring org-copy-subtree
C-c C-x C-y 从 kill ring 中粘贴子树 org-paste-subtree
C-y Depending on the options org-yank-adjusted-subtrees and org-yank- folded-subtrees, Org’s internal yank command will paste subtrees folded and in a clever way, using the same command as C-c C-x C-y. org-yank
C-c C-x c Clone a subtree by making a number of sibling copies of it. You will be prompted for the number of copies to make, and you can also specify if any timestamps in the entry should be shifted. org-clone-subtree-with-time-shift
C-c C-w 将条目或区域 refile 到不同的位置。 org-refile
C-c ^ 排序相同级别的条目。 org-sort
C-x n s 将缓冲区缩小到当前子树。 org-narrow-to-subtree
C-x n b 将缓冲区缩小到当前 block 。 org-narrow-to-block
C-x n w 加宽缓冲区以消除变窄。 widen
C-c * 使正常的文本行变为标题,重复操作可恢复成原样 org-toggle-heading

1.1.4 稀疏树

一个很重要的特性就是org有能力为被选中的信息构造出稀疏树,使得被选中信息突出显示,无关信息折叠显示。实践才是检测真理的唯一标准,试一试就知道具体是怎样优化你的工作了。

Table 4: 稀疏树
Key Desc Command
C-c / 本命令会触发sparse-tress命令界面,提示输入字符,来选择创建稀疏树的命令 org-sparse-tree
C-c / r 创建出和正则表达式匹配的稀疏树;标题匹配,标题可见; body匹配, 标题和body都可见;所以匹配高亮,当当前buffer通过编辑命令发送改变时,高亮消失,当然你可以通过 C-c C-c 主动取消高亮。 org-occur
M-g n 跳转到下一个匹配 next-error
M-g p 跳转到上一个匹配 previous-error

很有可能需要频繁创建特定搜索条件的稀疏树,可通过 org-agenda-custom-commands 来定义快速访问的快捷键(这个命令可用在agenda dispatcher中)。 如下:

1
2
;; the key C-c a f as a shortcut for creating a sparse tree matching the string ‘FIXME’.
(setq org-agenda-custom-commands '(("f" occur-tree "FIXME")))

The other sparse tree commands select headings based on TODO keywords, tags, or properties and will be discussed later in this manual. To print a sparse tree, you can use the Emacs command ps-print-buffer-with-faces which does not print invisible parts of the document. Or you can use C-c C-e C-v to export only the visible part of the document and print the resulting file.

1.2 列表

Within an entry of the outline tree, hand-formatted lists can provide additional structure. They also provide a way to create lists of checkboxes. Org supports editing such lists, and every exporter can parse and format them.

在大纲树的组织结构中,自定义格式的列表可以提供更多的组织结构。使我们得到一个复先框列表。 Org 可以处理这种列表,同时各个 exporter 可以解析和格式化。 Org 可识别 ordered 列表, unordered 列表, 和 description 列表。

  • Unordered 的列表项以 ‘-’, ‘+’ 或 ‘*’ 开始。
  • Ordered 的列表项以数字加在 ‘.’ 或 ‘)’ 开始。格式如下:‘1.’ 或 ‘1)’。 可自定义起始值,在文本开始出插入[@20],代表以20开始。
  • Description 列表项其实就是 unordered 列表项, 只在文本中间插入了分隔符 ‘::’ 。

同一个列表中项首行必须缩进一致。特别是 ordered 列表到了 ‘10.’ ,两位数字必须和其他数字左对齐。 若是下一行的缩进小于等于当前列表的缩进,则当前项终结。当所有项都终结,或者后面隔了两个空行时,列表终结。示例如下:

** Lord of the Rings
   My favorite scenes are (in this order)
   1. The attack of the Rohirrim
   2. Eowyn's fight with the witch king
       + this was already my favorite scene in the book
       + I really like Miranda Otto.
   Important actors in this film are:
   - Elijah Wood :: He plays Frodo
   - Sean Austin :: He plays Sam, Frodo's friend.

Org supports these lists by tuning filling and wrapping commands to deal with them correctly, and by exporting them properly. Since indentation is what governs the structure of these lists, many structural constructs like #+BEGIN_... blocks can be indented to signal that they belong to a particular item.

If you find that using a different bullet for a sub-list (than that used for the current list-level) improves readability, customize the variable org-list-demote-modify-bullet. To get a greater difference of indentation between items and their sub-items, customize org-list-indent-offset.

The following commands act on items when the cursor is in the first line of an item (the line with the bullet or number). Some of them imply the application of automatic rules to keep list structure intact. If some of these actions get in your way, configure org-list-automatic-rules to disable them individually.

当光标位于一项的首行时(带有项标志符的行),下面命令将作用于该项:

Table 5: 稀疏树
Key Desc Command
TAB 列表项像标题一样的被折叠,展开 org-cycle
TAB 用于还未输入文本信息的子项,第一个TAB变为子项,第二个TAB变为父项,第三个TAB恢复原有等级 (,->children->parent->initial)) org-cycle
M-RET 插入一个同级项(行首,把当前行转成列表项;行中,截断余下文本,在下一行生成列表项) org-insert-heading
M-S-RET 插入一个带 checkbox 的同级项(行为类似于M-RET)  
S-up/S-down 跳转到当前列表的上一项或者下一项  
M-up/M-down 和上一项或者下一项交换位置(同级之间)  
M-left/M-right 提升或者降低一项的等级,子项不变  
M-S-left/M-S-right 提升或者降低一项的等级,子项同等变化  
C-c C-c 当前项有 checkbox , 触发状态转换  
C-c - 循环改变将当前列表的项标志符  
C-c * 使列表项变为标题 (在当前位置生成子标题). org-toggle-heading
C-c C-* 使整个列表变成当前标题的子树 checkboxes 将变为 TODO 当未 unchecked 时  
S-left/right 循环改变将当前列表的项标志符  
C-c ^ Sort the plain list org-sort

1.3 Drawers

Sometimes you want to keep information associated with an entry, but you normally don’t want to see it. For this, Org mode has drawers. They can contain anything but a headline and another drawer.

You can interactively insert drawers at point by calling org-insert-drawer, which is bound to C-c C-x d. With an active region, this command will put the region inside the drawer. With a prefix argument, this command calls org-insert-property-drawer and add a property drawer right below the current headline. Completion over drawer keywords is also possible using M-TAB.

Visibility cycling on the headline will hide and show the entry, but keep the drawer collapsed to a single line. In order to look inside the drawer, you need to move the cursor to the drawer line and press TAB there. Org mode uses the PROPERTIES drawer for storing properties , and you can also arrange for state change notes and clock times to be stored in a drawer LOGBOOK. If you want to store a quick note in the LOGBOOK drawer, in a similar way to state changes, use C-c C-z Add a time-stamped note to the LOGBOOK drawer.

You can select the name of the drawers which should be exported with org-export-with-drawers. In that case, drawer contents will appear in export output. Property drawers are not affected by this variable: configure org-export-with-properties instead.

Drawers 如下所示:

** This is a headline
   Still outside the drawer
   :DRAWERNAME:
   This is inside the drawer.
   :END:
   After the drawer.

1.4 块

Org mode uses begin…end blocks for various purposes from including source code examples to capturing time logging information. These blocks can be folded and unfolded by pressing TAB in the begin line. You can also get all blocks folded at startup by configuring the option org-hide-block-startup or on a per-file basis by using

#+STARTUP: hideblocks
#+STARTUP: nohideblocks

1.5 脚注

A footnote is started by a footnote marker in square brackets in column 0, no indentation allowed. It ends at the next footnote definition, headline, or after two consecutive empty lines. The footnote reference is simply the marker in square brackets, inside text. Markers always start with fn:. For example:

The Org homepage[fn:1] now looks a lot better than it used to.
...
[fn:1] The link is: http://orgmode.org

Org mode extends the number-based syntax to named footnotes and optional inline definition. Here are the valid references:

[fn:name]
A named footnote reference, where name is a unique label word, or, for simplicity of automatic creation, a number.
[fn::This is the inline definition of this footnote]
A LATEX-like anonymous footnote where the definition is given directly at the reference point.
[fn:name:a definition]
An inline definition of a footnote, which also specifies a name for the note. Since Org allows multiple references to the same note, you can then use \[fn:name\] to create additional references.

Footnote labels can be created automatically, or you can create names yourself. This is handled by the variable org-footnote-auto-label and its corresponding #+STARTUP keywords. See the docstring of that variable for details.

示例如下: The Org homepage1 now looks a lot better than it used to.

Table 6: 脚注命令列表
Key Desc Command
C-c C-x f 当光标处于引用处时,跳转到它的定义;当光标处理定义处时,跳转到第一个引用处。其他情况下,新建一个脚注。当有前缀参数时,会提供一个菜单供选择操作,其中包括重新给脚注编号。 org-footnote-action
C-c C-c 当光标处于引用处时,跳转到它的定义;当光标处理定义处时,跳转到第一个引用处。当有前缀参数时,行为和 C-c C-x f 一样,提供同样操作菜单。  
C-c C-o 脚注标签也是指向相应定义/引用的链接,您可以使用常用(链接)命令来跟踪这些链接。 org-open-at-point
C-c ='= 在独立的窗口中,编辑引用关联的脚注定义。窗口可通过 C-c ='= 关闭 org-edit-special

当 C-c C-x f 命令加上附加前缀参数时(C-u C-c C-x f) ,一个操作菜单被提供:

s    Sort the footnote definitions by reference sequence.  During editing,
     Org makes no effort to sort footnote definitions into a particular
     sequence.  If you want them sorted, use this command, which will
     also move entries according to org-footnote-section.  Automatic
     sorting after each insertion/deletion can be configured using the
     option org-footnote-auto-adjust.
r    Renumber the simple fn:N footnotes.  Automatic renumbering
     after each insertion/deletion can be configured using the option
     org-footnote-auto-adjust.
S    Short for first r, then s action.
n    Normalize the footnotes by collecting all definitions (including
     inline definitions) into a special section, and then numbering them
     in sequence.  The references will then also be numbers.
d    Delete the footnote at point, and all definitions of and references
     to it.

1.6 The Orgstruct minor mode

If you like the intuitive way the Org mode structure editing and list formatting works, you might want to use these commands in other modes like Text mode or Mail mode as well. The minor mode orgstruct-mode makes this possible. Toggle the mode with M-x orgstruct-mode RET, or turn it on by default, for example in Message mode, with one of:

1
2
(add-hook 'message-mode-hook 'turn-on-orgstruct)
(add-hook 'message-mode-hook 'turn-on-orgstruct++)

1.7 Org 的语法

A reference document providing a formal description of Org’s syntax is available as a draft on Worg, written and maintained by Nicolas Goaziou. It defines Org’s core internal concepts such as headlines, sections, affiliated keywords, (greater) elements and objects. Each part of an Org file falls into one of the categories above.

To explore the abstract structure of an Org buffer, run this in a buffer:

M-: (org-element-parse-buffer) RET

It will output a list containing the bu↵er’s content represented as an abstract structure. The export engine relies on the information stored in this list. Most interactive commands (e.g., for structure editing) also rely on the syntactic meaning of the surrounding context.

You can check syntax in your documents using org-lint command.

2 表格

Org 提供了一个快速直观的表编辑器。 使用 Emacs 内嵌的 calc 的包可支持类似于制表软件的操作。

2.1 内置表编辑器

Org 能够很容易地格式化 ASCII 文本表格。 任何把'|'作为首个非空白字符的行都被视为表的一部分。 '|'也是列分隔符。 表如下所示:

名字 手机号 年龄
brantou 170xxxxxxxx 18

在表格内键入 TAB , RET 或 C-c C-c 时,表格都会自动重新对齐。 TAB 也可以移动到下一个表格区域( RET 进入下一行),并在表的末尾或水平线之前创建新的表行。 表的缩进由第一行设置。 以"|-"开头的任何行都被视为水平分隔符行,并在下一个重新对齐时展开。所以,要创建上面的表,你只需要键入

| 名字 | 手机号 | 年龄 |
|-

然后按 TAB 扩展表格。 更快的是键入 |名称|手机号|年龄 后, 再键入 C-c RET 。

在表格区域中输入文本时,Org以特殊方式处理DEL,Backspace和所有字符键,以便插入和删除避免移动其他字段。 此外,当使用TAB,S-TAB或RET将光标移动到新的表格区域后会自动填充空格。 如果这种行为对您太不可预测,请配置选项 org-enable-table-editor 和 org-table-auto-blank-field 。

2.1.1 创建和转换

=C-c= =|=                 ~org-table-create-or-convert-from-region~

将活动区域转换为表。 如果每行包含至少一个TAB字符,则认为 TAB 是分隔符。 如果每一行都包含逗号,则逗号作为分隔(CSV)。 如果不是,则将行以空格为分隔符。 您可以使用前缀参数强制指定分隔符: C-u 强制CSV, C-u C-u 强制TAB, C-u C-u C=u 将提示正则表达式匹配分隔符,数值参数N表示至少N个连续空格,或者 一个TAB将是分隔符。 如果没有活动区域,此命令将创建一个空的组织表。

2.1.2 调整和区域移动

Key Description Command
C-c C-c 重新对齐表格,不移动到其他字段。 org-table-align
C-c SPC 使用空格填充当前区域 org-table-blank-field
<TAB> 重新对齐表格,移动到下一区域。 如有必要,创建一个新行。 org-table-next-field
S-TAB 重新对齐,移动到上一区域。 org-table-previous-field
RET 重新对齐表格并向下移动到下一行。 如有必要,创建一个新行。 org-table-next-row
M-a 移动到当前表区域的开头,或移动到上一个区域。 org-table-beginning-of-field
M-e 移动到当前表区域的结尾,或移动到上一个区域。 org-table-end-of-field

2.1.3 列和行编辑

Key Description Command
M-left \ M-right 向左/向右移动当前列 org-table-move-column-left\right
M-S-left 删除当前列 org-table-delete-column
M-S-right 在光标位置的左侧插入一个新列 org-table-insert-column
M-up \ M-down 向上/向下移动当前行 org-table-move-row-up\down
M-S-up 删除当前行或水平分隔线 org-table-kill-row
M-S-down 在当前行上方插入新行。 使用前缀参数,该行在当前行下创建 org-table-insert-row
C-c - 在当前行下插入水平线。 使用前缀参数,在当前行之上创建 org-table-insert-hline
C-c RET 在当前行下插入水平线,将光标移动到该线下面的行 org-table-hline-and-move
C-c ^ 对区域中的表行进行排序 org-table-sort-lines

2.1.4 区域

Key Description Command
C-c C-x M-w 将矩形区域从表复制到特殊剪贴板。 点和标记确定矩形的边缘字段。 如果没有活动区域,只复制当前字段。 该过程忽略水平分隔线。 org-table-copy-region
C-c C-x C-w 将矩形区域从表格复制到特殊剪贴板,并将矩形中的所有字段都留空。 所以这是“剪切”操作。 org-table-cut-region
C-c C-x C-y 将矩形区域粘贴到表中。 左上角在当前字段中结束。 所有涉及的字段将被覆盖。 如果矩形不适合当前表格,则根据需要放大表格。 该过程忽略水平分隔线。 org-table-paste-rectangle
M-RET 在光标位置分割当前字段,并将其余部分移动到下面的行。 如果存在活动区域,并且点和标记都在同一列中,则列中的文本将包装为给定行数的最小宽度。 数字前缀参数可用于更改所需行的数量。 如果没有区域,但您指定了前缀参数,则将当前字段设置为空,并将内容追加到上面的字段。 org-table-wrap-region

2.1.5 计算

Key Description Command
C-c + 将当前列中的数字或由活动区域定义的矩形中的数字相加。 结果显示在echo区域中,可以用C-y插入。 org-table-sum
S-RET 当前字段为空时,从上面的第一个非空区域复制。 当不为空时,将当前区域复制到下一行,并将光标与其一起移动。 org-table-copy-down

2.1.6 杂项

Key Description Command
C-c ` 在单独的窗口中编辑当前区域。 这对于不完全可见的区域很有用。当使用C-u前缀调用时,仅仅使整个字段可见,以便可以在当前位置编辑 。 当使用两个C-u前缀调用时,使编辑器窗口跟随光标在表移动,并始终显示光标所在区域。 当光标离开表时,或者当您用C-u C-u C-c`重复此命令时,跟随模式将自动退出。 org-table-edit-field
M-x org-table-import RET 将文件作为表导入。 表格应该是TAB或空格分隔。 org-table-import
C-c \vert 也可以通过将表格文本粘贴到 Org buffer,使用 C-x C-x 选择粘贴的文本,然后使用C-c | 命令(请参阅上面的创建和转换)。 org-table-create-or-convert-from-region
M-x org-table-export RET 导出表,默认情况下作为 TAB 分隔的文件。 用于与例如电子表格或数据库程序进行数据交换。 用于导出文件的格式可以在选项 org-table-export-default-format 中配置。 您还可以使用属性 TABLEEXPORTFILE 和 TABLEEXPORT_ FORMAT 来指定子树中的表导出的文件名和格式。 Org支持导出表格的相当一般格式。 org-table-export

你可能因为‘|’开始的行,妨碍到你,而不喜欢自动表编辑器,你可以用下面的语句来关闭

(setq org-enable-table-editor nil)

然后唯一的表命令 C-c C-c 仍然工作, 做一个手动重新对齐。

2.2 列宽和对齐

列的宽度由表编辑器自动确定。 并且还可以从列中包含的数据类型(数字或者非数字)自动确定列的对齐方式。 有时一个区域或几个区域需要包含很多文本信息,会导致信息展示和编辑的诸多不便。 或者你想设定固定宽度的几列,而不管内容如何。 要设置列的宽度,列中任何位置的一个字段可能只包含字符串“N”,其中“N”是指定列的宽度(以字符为单位)的整数。 接下来重新对齐,然后将此列的宽度设置为此值。

<img src="/images/table-column-width.jpg" />

设定固定宽度后,长文本将会裁剪展示,多余部分用字符串 => 来替代展示。 要查看全文,请将鼠标悬停在该字段上—工具提示窗口(tool-tip window)将显示完整的内容。 要编辑这样一个区域,可使用 C-c ` 。 这将打开一个的新窗口。 编辑后用 C-c C-c 来提交编辑内容,并关闭窗口。

当浏览包含有固定宽度表的文件时,必需的隐藏内容尚未发生,需要对齐表来隐藏内容,来变美观。 可设置 org-startup-align-all-tables 是浏览时对文件中的所有表进行重新调整,但这样会减慢文件打开的速度。 也可以在每个文件中设置此选项:

#+STARTUP: noalign
#+STARTUP: align

如果不喜欢默认自动对齐的方式,您可以使用 <r> ,*<c>* 或者 <l> 来自定义对齐方式。 还可以将对齐和固定宽度组合使用,如下所示: <r10> 。 在导出文档时,将自动删除仅包含这些格式化信息的行。

2.3 列组

当Org导出表时,默认情况下不会有垂直线,因为在视觉上一般来说更令人满意。 然而,偶尔,垂直线对于将表结构化成一组列可能是有用的,就像水平线可以对于一组行所做的那样。 为了指定列组,您可以使用第一个字段仅包含"/"的特殊行。 其他字段可以包含'<'表示此列应该启动一个组,'>'表示组的结束,或'<>'('<'和'>'之间没有空格) 当前列自己一组。 导出后,列组之间的边界将用垂直线标记。 示例如下:

<img src="/images/table-column-groups.jpg" />

效果如下(好像没有效果):

N N2 N3 N4 sqrt(n) sqrt[4](N)
2 4 8 16 1.4142136 1.1892071
3 9 27 81 1.7320508 1.3160740

只插入列组启动器也是足够的:

<img src="/images/table-column-group-start.jpg" />

N N2 N3 N4 sqrt(n) sqrt[4](N)
2 4 8 16 1.4142136 1.1892071
3 9 27 81 1.7320508 1.3160740

2.4 The Orgtbl minor mode

If you like the intuitive way the Org table editor works, you might also want to use it in other modes like Text mode or Mail mode. The minor mode Orgtbl mode makes this possible. You can always toggle the mode with M-x orgtbl-mode RET. To turn it on by default, for example in Message mode, use

(add-hook 'message-mode-hook 'turn-on-orgtbl)

Furthermore, with some special setup, it is possible to maintain tables in arbitrary syntax with Orgtbl mode. For example, it is possible to construct LATEX tables with the underlying ease and power of Orgtbl mode, including spreadsheet capabilities.

2.5 电子表格

请参阅如下内容:

  • Org as a spreadsheet system: a short introduction
  • Org as a spreadsheet system: using Emacs lisp as formulas

2.6 Org-Plot

请参阅如下内容:

  • Plotting tables in Org-Mode using org-plot
  • http://www.gnuplot.info/

3 超链接

就如 HTML 一样, Org 提供文件内部链接,到其他文件,Usenet文章,电子邮件等外部链接。

3.1 链接格式

Org 能够识别类似URL链接的文本,并处理成可点击的链接。 通用链接格式如下所示:

[[link][description]]  或者 [[link]]

一旦链接完成,链接样式将发生变化,显示 description 而不是 [[link] [description]] 或 link 而不是 [ [link]]] 。 可以直接编辑链接的可见部分。 请注意,这可以是 link 部分(如果没有 description )或 description 部分。 要编辑不可见的“链接”部分,只需在链接上键入 C-c C-l 。 在链接的头和尾可删除链接不可见的边际括号,使得链接不完整,内部再次显示为纯文本。 插入缺失的括号将再次隐藏链接内部。 要显示所有链接的内部结构,可用菜单条目 Org->Hyperlinks->Literal links 。

3.2 内部链接

如果一个链接不是URL形式的,它被当做当前文件中的内部链接。 最重要的情况是像 [ [#my-custom-id]] 这样的链接,它将链接到 CUSTOMID 属性是 my-custom-id 的条目。 自己要负责确保这些自定义ID在文件中是唯一的。 诸如 [ [MyTarget]] 或 [[MyTarget] [Findmytarget]] 的链接会在当前文件的文本中搜索。 在链接上输入 C-c C-o 或 鼠标点击时,会跳转到链接匹配处。 自定义ID的链接将指向相应的标题。

文本链接的首选匹配是 dedicated target :双角括号中的相同字符串,如 ←← My Target→→ 。 如果没有 dedicated target ,链接将尝试匹配缓冲区内元素的精确名称。 使用 #+NAME 关键字进行命名,必须将其放在引用的元素之前的行中,如以下示例所示:

#+NAME: My Target
| a  | table      |
|----+------------|
| of | four cells |

如果以上都没有成功,Org将搜索与链接文本完全相同的标题(也会搜索 TODO 关键字和标签)。

在导出过程中,内部链接被用于标记对象(并分配一个数字)。 标记的对象将被指向它们的链接引用。 特别地,没有 description 的链接将显示为分配给标记对象的编号。 以下摘录自 Org 缓冲区

- one item
- <<target>> another item
Here we refer to item [[target]].

导出时,最后一句将显示为 Here we refer to item 2 。

在非 Org 文件中,搜索将查找链接文本中的单词。 在上面的例子中搜索将是 my Target 。 链接后,将 mark 推到 Org 自己的 mark ring 上。 可使用 C-c & 返回到前一个位置。 直接连续使用这个命令多次可以回到前面记录的位置。

3.2.1 Radio targets

Org 可自动将正常文本中某些目标名称的任何出现转换为链接。 所以没有明确创建一个链接,文本就连接到 Radio targents 的位置。 Radio targets 由三角形括号括起来, 如 ←←← My Target→→→ 导致正常文本中的每个出现的 my target 被激活为链接。 仅当文件首次加载到Emacs中时,才会自动扫描 Radio targets 。 要在编辑过程中更新 Radio targets 列表,请在光标处于 Radio targets 位置时按 C-c C-c 。

3.3 外部链接

Org 支持链接到文件,网站,Usenet和电子邮件,BBDB数据库条目和链接到IRC对话及其日志。 外部链接是类似URL的 locators 。 它们以一个简短的识别字符串后面跟一个冒号开始。 冒号后没有空格。 下面列表显示每个链接类型的示例。

http://www.astro.uva.nl/~dominik           on the web
doi:10.1000/182                            DOI for an electronic resource
file:/home/dominik/images/jupiter.jpg      file, absolute path
/home/dominik/images/jupiter.jpg           same as above
file:papers/last.pdf                       file, relative path
./papers/last.pdf                          same as above
file:/myself@some.where:papers/last.pdf    file, path on remote machine
/myself@some.where:papers/last.pdf         same as above
file:sometextfile::NNN                     file, jump to line number
file:projects.org                          another Org file
file:projects.org::some words              text search in Org file
file:projects.org::*task                   heading search in Org file
docview:papers/last.pdf::NNN               open in doc-view mode at page
id:B7423F4D-2E8A-471B-8810-C40F074717E9    Link to heading by ID
news:comp.emacs                            Usenet link
mailto:adent@galaxy.net                    Mail link
mhe:folder                                 MH-E folder link
mhe:folder#id                              MH-E message link
rmail:folder                               RMAIL folder link
rmail:folder#id                            RMAIL message link
gnus:group                                 Gnus group link
gnus:group#id                              Gnus article link
bbdb:R.*Stallman                           BBDB link (with regexp)
irc:/irc.com/#emacs/bob                    IRC link
info:org#External links                    Info node or index link
shell:ls *.org                             A shell command
elisp:org-agenda                           Interactive Elisp command
elisp:(find-file-other-frame "Elisp.org")  Elisp form to evaluate

链接应包含在双括号中,当然可能想要显示的描述性文本而不是URL(参见链接格式),例如:

[[http://www.gnu.org/software/emacs/][GNU Emacs]]

如果描述是文件名或指向图像的URL,则HTML导出将内嵌图像作为可点击按钮。 如果没有任何描述和链接指向图像,该图像将被内联到导出的HTML文件中。

Org 能识别出正常文本中的外部链接,并将其作为链接激活。 如果空格必须是链接的一部分(例如在 bbdb:[Richard Stallman] 中), 或者如果需要消除关于链接结尾的歧义,请将其括在方括号中。

3.4 处理链接

Org 为了正确的创建链接,插入链接和跟随链接,提供了很多快捷键。

Key Description Command
C-c l 存储当前位置的链接。 这是一个全局命令,可以在任何缓冲区中使用它来创建链接。 链接将被存储以备将来插入 Org 的缓冲区。 创建什么样的链接取决于当前的缓冲区。 org-store-link
C-c C-l 插入链接。 将提示将链接插入缓冲区。 可以键入链接,使用内部链接的文本或上述示例中提到的链接类型前缀之一。 该链接将被插入到缓冲区,以及一个描述性的文本。 如果在调用此命令时选择了某些文本,则所选文本将成为默认描述。 org-insert-link
C-u C-c C-l 当使用 C-u 前缀参数调用 C-c C-l 时,将插入文件链接,可以使用文件名来完成文件选择。当前用到是相对路径,若是想要绝对路径可用两个 C-u 前缀。  
C-c C-l 当光标在已有链接上时, C-c C-l 允许编辑链接的链接和描述部分。  
C-c C-o 打开当前位置的链接。如果要覆盖默认应用程序并使用Emacs访问文件,请使用 C-u 前缀。 如果要避免在Emacs中打开,请使用 C-u C-u 前缀。如果光标位于标题上,但不在链接上,则打开标题中所有链接。 org-open-at-point
RET 当 org-return-follow-link 设置时,RET也将跟随当前位置的链接。  
C-c C-x C-v 触发图片链接内联显示。当用前缀参数调用时,还会显示具有描述信息的图片链接。 可以通过配置变量 org-startup-with-inline-images 使内联图片在启动时显示。 org-toggle-inline-images
C-c % Push the current position onto the mark ring, to be able to return easily. Commands following an internal link do this automatically. org-mark-ring-push
C-c & 跳回到记录位置。 A position is recorded by the commands following internal links, and by C-c %. Using this command several times in direct succession moves through a ring of previously recorded positions. org-mark-ring-goto
C-c C-x C-n/p 向前/向后移动到缓冲区中的下一个链接。 org-next/previous-link

3.5 在Org之外使用链接

可以插入和跟踪具有Org语法的链接,不仅在组织中,而且可以在任何Emacs缓冲区中。 为此,应该创建两个全局命令,如下:

1
2
(global-set-key "\C-c L" 'org-insert-link-global)
(global-set-key "\C-c o" 'org-open-at-point-global)

3.6 链接缩写

长的URL输入起来会很麻烦,同时在文档中类似的链接可能会很频繁的出现。 为此,你可能需要使用链接缩写。 链接缩写看起来如下所示:

[[linkword:tag][description]]

tag 是可选的, linkword 必须是一个单词,以字母开头,后跟字母,数字,' - '和''。 根据将链接缩写词与替换文本相关联的变量 org-link-abbrev-alist 中的信息来解析缩写。 定义如下所示:

1
2
3
4
5
6
7
(setq org-link-abbrev-alist
'(("bugzilla" . "http://10.1.2.9/bugzilla/show_bug.cgi?id=")
("url-to-ja" . "http://translate.google.fr/translate?sl=en&tl=ja&u=%h")
("google" . "http://www.google.com/search?q=")
("gmap" . "http://maps.google.com/maps?q=%s")
("omap" . "http://nominatim.openstreetmap.org/search?q=%s&polygon=1")
("ads" . "http://adsabs.harvard.edu/cgi-bin/nph-abs_connect?author=%s&db_key=AST")))

如果替换文本包含字符串 %s ,它将被标签所替换。 使用 %h 而不是 %s ,是因为需要对标签进行url编码(参见上面示例,需要对URL参数进行编码)。 使用 %(my-function) 将标签传递给自定义函数 ,并将其替换为生成的字符串。 如果替换文本不包含任何说明符,则只需把标签添加到替换文本后即可创建链接。

如果只需要单个Org缓冲区的特殊缩写,可以在文件中定义它们

#+LINK: bugzilla  http://10.1.2.9/bugzilla/show_bug.cgi?id=
#+LINK: google    http://www.google.com/search?q=%s

3.7 文件链接的搜索选项

参见Org-mode手册中相关章节

3.8 自定义搜索

参见Org-mode手册中相关章节

4 待办事项

Org-mode 不把 TODO 列表作为单独的文档来维护。 相反, TODO 列表是笔记的组成部分,因为它通常产生于记录笔记时! 使用 Org-mode ,只需将树中的任何条目标记为 TODO 就可构造出 TODO 列表。 这种方式,信息不会冗余重复,并且始终显示 TODO 项出现的整个上下文。 当然,这种用于管理 TODO 项的方式会将它们分散在各个笔记文件中。 Org-mode 通过提供一些方法使我们可以把它们看作一个整体来处理。

4.1 基础的待办事项功能

以 TODO 关键字开始的任意标题都会变为代办事项,例如:

*** TODO Write letter to Sam Fortune
Key Desc Command
C-c C-t 转换当前项的TODO状态 _,-> (unmarked) -> TODO -> DONE –._ org-todo
C-u C-c C-t 当TODO关键字没有选择时,使用补全选择特定的关键字; 否则强制循环遍历TODO状态,没有提示。  
S-left/right 选择之后/之前的TODO状态,像是循环。  
C-c / t 构造出TODO列的稀疏树;折叠整个缓冲区,但显示所有TODO项( not-DONE 状态)和其上的标题层次结构。 使用前缀参数(或使用 C-c / T ),搜索特定的TODO。 系统提示输入关键字,还可以输入KWD1 | KWD2 | …等关键字,列出与这些关键字中的任何一个匹配的项。 使用数字前缀参数N,在选项 org-todo-keywords 中显示第N个关键字的树。 使用两个前缀参数,找到所有TODO状态,无论是完成还是未完成。 org-show-todo-tree
C-c a t 展示全局 TODO 列表;将所有agenda文件中的TODO项( not-DONE 状态)收集到一个缓冲区中。 新的缓冲区将处于 agenda-mode ,它提供了从新的缓冲区检查和操作TODO项的命令。 org-todo-list
S-M-RET 在当前项之后插入新的 TODO 项 org-insert-todo-heading

注: 改变 TODO 状态也可触发标签发生变更。 请参阅 org-todo-state-tags-triggers 文档以了解详细信息, 也可可查看How to automatically trigger a change in TODO state in Emacs org-mode。

4.2 待办事项扩展

默认情况下, 待办事项只能为以下两种状态之一: TODO 和 DONE 。 Org-mode 允许使用 TODO 关键字(存储在 org-todo-keywords )以更复杂的方式对 TODO 项目进行分类管理。 通过特殊设置, TODO 关键字系统可在不同的文件对不同的工作流程进行定制。

4.2.1 工作流状态应用

可以使用 TODO 关键字来表示项目进行过程中工作流状态,例如:

(setq org-todo-keywords
   '((sequence "TODO" "FEEDBACK" "VERIFY" "|" "DONE" "DELEGATED")))

垂直条将 TODO 关键字(需要处理的状态)从DONE状态分离(无需进一步操作)。 如果不提供垂直条,则最后一个状态用作 DONE 状态。 使用以上设置,命令 C-c C-t 将待办事项从 TODO 循环到 FEEDBACK ,然后到 VERIFY ,最后到 DONE 和 DELEGATED 。 也可以使用数字前缀参数快速选择特定状态。 例如, C-3 C-c C-t 将立即将状态更改为VERIFY。 或者可以使用 S-left/right 向后/向前遍历序列。

4.2.2 类型标示应用

第二种可能性是使用TODO关键字来指示待办事项的隶属于不同类型。 例如,可能希望指出项目是 work 或 home 。 或者,当在一个项目中与多个人合作时,可能需要通过使用他们的名字作为 TODO 关键字来将项目任务直接分配给个人。 如下配置:

(setq org-todo-keywords '((type "Fred" "Sara" "Lucy" "|" "DONE")))

在这种情况下,不同的关键字不表示序列,而是不同的类型。 所以正常的工作流程是将任务分配给一个人,然后将其标记为DONE。 Org-mode 通过调整命令 C-c C-t 的工作机制来支持这种风格。 当连续使用多次时,它仍将循环遍历所有名称,以便首先为任务选择正确的类型。 但是,当经过一段时间后返回该项目并再次执行 C-c C-t ,它将从任何名称直接切换到 DONE 。 使用前缀参数或完成快速选择一个特定的名称。 还可以使用 C-c / t 的数字前缀来查看稀疏树中特定 TODO 类型的项目。 例如,要查看Lucy所做的一切事情,使用 C-3 C-c / t 。 要将Lucy的所有项目从所有议程文件收集到一个单独的库中,还可以在创建全局TODO列表时使用数字前缀参数: C-3 C-c a t 。

4.2.3 单个文件中多个关键字集合

有时可能需要并行使用不同的TODO关键字集。 例如,可能需要具有基本的 TODO / DONE ,还有一个修复错误的工作流程,以及指示某个项目已被取消的单独状态(因此它不是 DONE ,也不需要执行操作)。 设置如下所示:

(setq org-todo-keywords
      '((sequence "TODO" "|" "DONE")
	(sequence "REPORT" "BUG" "KNOWNCAUSE" "|" "FIXED")
	(sequence "|" "CANCELED")))

这些关键字应该是不同的,这有助于 Org-mode 跟踪给定条目应该使用哪个子序列。 在这个设置中, C-c C-t 只能在一个子序列中运行, 所以它从 DONE 切换到(无)到 TODO , 从 FIXED 切换到(无)到 REPORT 。 因此,需要一种机制来正确初始选择序列。 除了显式的键入关键字或使用补全外,还可应用以下命令:

C-u C-u C-c C-t C-S-right/left

这些键从一个 TODO 子集跳到下一个。 在上面的例子中, C-u C-u C-c C-t 或 C-S-right 将从 TODO 或 DONE 跳到 REPORT , 而第二行中的任何一个字都可跳转到 CANCELED 。

S-right/left

S-right/left 并从所有集合中遍历所有关键字,例如在上面的例子中,S-right将从DONE切换到REPORT。

4.2.4 快速访问代办状态

如果要快速将条目更改为任意TODO状态,而不是循环遍历状态,则可以设置单个字符来快速访问状态的键。 这是通过在每个关键字后面的括号中添加选择字符来完成的。

(setq org-todo-keywords
     '((sequence "TODO(t)" "|" "DONE(d)")
       (sequence "REPORT(r)" "BUG(b)" "KNOWNCAUSE(k)" "|" "FIXED(f)")
       (sequence "|" "CANCELED(c)")))

如果按C-c C-t,后按选择键,则条目将切换到此状态。 SPC可用于从条目中删除任何TODO关键字。

4.2.5 为文件设置独立的关键字集合

在不同文件中使用 TODO 机制的不同方面是非常有用的。 对于文件本地设置,需要在文件中添加专用行,仅为该文件设置关键字和仅对当前文件起效。 例如,要设置上述两个示例之一,需要在文件中包含以下任何一行:

#+TODO: TODO FEEDBACK VERIFY | DONE CANCELED

或者

#+TYP_TODO: Fred Sara Lucy Mike | DONE

并行使用几组的设置如下:

#+TODO: TODO | DONE
#+TODO: REPORT BUG KNOWNCAUSE | FIXED
#+TODO: | CANCELED

在更改其中一行后,在行中使用 C-c C-c ,以使变更生效。

4.2.6 代办事项关键字的样式

Org-mode 突出显示具有特殊样式的TODO关键字:关键字的 org-todo 表示某个项目仍然需要执行,对于表示项目完成的关键字 org-done 。 如果使用两种以上的不同状态,可能需要为其中某些状态使用特殊样式。 可使用选项 org-todo-keyword-faces 来完成。 例如:

(setq org-todo-keyword-faces
      '(("TODO" . org-warning) ("STARTED" . "yellow")
	("CANCELED" . (:foreground "blue" :weight bold))))

4.2.7 待办事项的依赖关系

Org 结构(层次结构和列表)可以轻松定义TODO依赖关系。 通常,在将所有子任务标记为 DONE 之前,不应将父 TODO 任务标记为 DONE 。 有时,对于一些(子)任务有一个逻辑顺序,所以在完成上面的所有兄弟任务之前,一个任务不能被执行。 如果设置自定义选项 org-enforce-todo-dependencies ,Org将会阻塞任务从 TODO 更改为 DONE ,而它的子项不是DONE。 此外,如果条目具有 ORDERED 属性,则每个子项将被阻塞,直到所有较早的兄弟节点被标记为 DONE 。 设置 org-enforce-todo-dependencies,如下所示:

(setq org-enforce-todo-dependencies t)

依赖关系示例如下:

* TODO Blocked until (two) is done
** DONE one
** TODO two

* Parent
  :PROPERTIES:
  :ORDERED:  t
  :END:
** TODO a
** TODO b, needs to wait for (a)
** TODO c, needs to wait for (a) and (b)

可以使用 NOBLOCKING 属性确保从不阻塞输入:

* This entry is never blocked
  :PROPERTIES:
  :NOBLOCKING: t
  :END:
C-c C-x o

切换当前条目的 ORDERED 属性。 ORDERED 属性只适用于当前项,而不是像标签一样可继承。 但是,如果要使用标签跟踪该属性的值,以便更好地查看,请自定义选项 org-track-ordered-property-with-tag 。

C-u C-u C-u C-c C-t
改变 TODO 状态,规避任何状态阻塞。

如果设置选项 org-agenda-dim-blocked-tasks ,则由于这些依赖关系而无法关闭的TODO条目将以渐变字体显示,甚至在议程视图中不可见。 还可以通过查看复选框来阻止 TODO 状态的更改。 如果设置了选项 org-enforce-todo-checkbox-dependencies ,则将禁止具有未选中复选框的条目切换到 DONE 。 如果需要更复杂的依赖关系结构,例如不同树或文件中的条目之间的依赖关系,请查看模块 org-depend.el 。

4.3 进度记录

4.3.1 关闭项目

4.3.2 追踪TODO状态变化

4.3.3 追踪你的习惯

4.4 优先级

4.5 任务分解

4.6 复选框

5 标签

6 属性

7 日期和时间

8 捕获——转发——存档

9 议程视图

Footnotes:

1

org-mode 官方链接地址: http://orgmode.org

Last Updated 2017-10-13 Fri 17:33.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)

Org-mode的语法解读

发表于 2017-03-11 | 分类于 org-mode |

原文Org Syntax (draft)1由 Nicolas Goaziou 编辑,维护。本文只做学习之用。

本文档描述和说明被org的解析器和导出器框架使用的语法,当然还有几个对于当前语法的意见和建议。

在 Org 语法中核心概念是: 只有 headlines, sections, planning lines 和 property drawers 四种语法结构是上下文无关的2, 3; 其他语法结构只能存在于特定 Environments 之中。

Environments 从大到小(作用范围的尺度来做分类标准,从最宽到最窄),大致可分为三类: "Greater element", "Element" 和 "Object"。 Element 被用到了两个类的命名中,Greater 和 non-Greater, 这代表了什么呢?代表了这两类有共通之处,即它们的上下文都会被清除,重新初始化。

Paragraph 是最小的语法单元。 定义 Element 的子语法结构和 Paragraph 同级,即不能包含 Paragraph 或者被包含在 Paragraph 中。 一个 Object 可以作为一部分被一个 Element 所包含。 Greater element 的任意部分都可以是一个 Element 。

<!– more –>

空行属于在它们之前结束的最大 Element 。例如,在列表中,之间的空行属于它们之前的那一项,但列表末尾的空行属于当前列表 Element 。

除非特别说明,大小写默认不敏感。

1 Headlines and Sections

Headline 定义如下:

STARS KEYWORD PRIORITY TITLE TAGS

STARS 是一个从第0列开始的字符串,至少包含一个星号(如果加载了 org-inlinetask 库,则上限为 org-inlinetask-min-level ),并以空格字符结尾。 星号的个数代表标题的等级。它是标题中唯一必须的部分。

KEYWORD 是一个TODO关键字,它必须被定义在 org-todo-keywords-1 的列表。 大小写敏感。

PRIORITY 是一个优先级标示(priority cookie)。示例: [#A] 。

TITLE 可以由换行符以外的任意字符组成。 标题下的内容匹配了搜索条件,代表此标题匹配。

TAGS 由 : 分隔的多个单词组成, 单词可由任何字母数字字符, _ , @ , # 或 % 组成。

有效标题的示例,如下:

*

** DONE

*** Some e-mail

**** TODO [#A] COMMENT Title :tag:a2%:

若标题中的第一个单词是 org-comment-string ,当前标题将被作为 /"commented"/ 。 大小写敏感。 若标题中的第一个单词是 org-quote-string ,当前标题将被作为 /"quoted"/ 。 大小写敏感。

若其标题是 org-footnote-section 将被作为 /"footnote section"/。 大小写敏感。

若 org-archive-tag 是它的标签之一,它被作为 /"archived"/ 。 大小写敏感。

标题可直接包含一个段落(可选),再跟任意数量的更深级别的标题(递归定义)。 一个段落可直接包含任意 Greater elelment 或 Element 。 只有标题可以包含段落。 文档中的第一个标题之前的文本除外,因为它属于一个段落。

作为示例,请考虑以下文档:

An introduction.

* A Headline 

  Some text.

** Sub-Topic 1

** Sub-Topic 2

*** Additional entry 

** QUOTE Another Sub-Topic

   Some other text.

其内部结构可概括为:

(document
 (section)
 (headline
  (section)
  (headline)
  (headline
   (headline))
  (headline
   (quote-section))))

2 Affiliated Keywords

除了inlinetasks, items, planning, clocks, node properties 和 table rows 之外,其他的任意的 Element 类型都可为其指定属性。

在选定的 Element 之前添加命名为 Affiliated keywords 的特定关键字,可指定属性的(在 Element 之前插入"affiliated keywords",不允许两者之前存在空行)。

Affiliated keywords 是建立在以下模式之上的: "#+KEY: VALUE", "#+KEY[OPTIONAL]: VALUE" 或者 "#+ATTR_BACKEND: VALUE" 。

KEY 可以是 "CAPTION", "HEADER", "NAME", "PLOT" 或 "RESULTS" 中的任意一个.

BACKEND 是一个由字母,数字,连字符或下划线组合而成的字符串。

OPTIONAL 和 VALUE 可以包含除换行符以外的任意字符。 只有"CAPTION"和"RESULTS"可以有可选值。

如果 KEY 为"CAPTION"或"HEADER",或者其模式为"#+ATTR_BACKEND:VALUE",则 Affiliated keywords 可以多次出现。

"CAPTION","AUTHOR","DATE"和"TITLE"可以包含 Object 及其可选值(如果适用)。

3 Greater Elements

除非特别说明, Greater elements 可以直接包含任何其他 Element 或 除了下面之外的 Greater element :

  • 同样类型的 Element
  • node properties, 只存在于property drawers 中,
  • items, 只存在于plain lists 中。

3.1 Greater Blocks

Greater blocks 由以下模式组成:

#+BEGIN_NAME PARAMETERS
CONTENTS
#+END_NAME

NAME 可以由任意非空白字符组成。

PARAMETERS 可以包含除换行符以外的任意字符,可以省略。

如果 NAME 是 CENTER ,表示当前 Greater block 是一个"center block"。 如果是 QUOTE ,表示是一个"quote block"。

如果 Block 既不是 center block , quote block 或 block element,则是 special block 。

CONTENTS 可以包含任何 Element ,除了: Block 自己的结束行 #+END_NAME 。 此外,以星号开头的行必须用逗号引号。

3.2 Drawers and Property Drawers

Drawer 的模式如下:

:NAME:
CONTENTS
:END:

NAME 可以包含词组字符(word-constituent characters),连字符和下划线。

NAME 必须是"PROPERTIES"或属于 org-drawers 所定义列表。

如果 NAME 是 PROPERTIES ,则 Drawer 即为 property drawer 。

CONTENTS可以包含任何 Element ,除了 Drawer 。

在 Property drawer 中,*CONTENTS* 只能包含节点 node property Element 。其他类型 Drawer ,它可以包含任何 Element ,除了另一个 Drawer 或 Property drawer 。


It would be nice if users hadn't to register drawers names before using them in org-drawers (or through the #+DRAWERS: keyword). Anything starting with ^[ \t]*:\w+:[ \t]$ and ending with ^[ \t]*:END:[ \t]$ could be considered as a drawer. — ngz

3.3 Dynamic Blocks

Dynamic blocks 的模式是:

#+BEGIN: NAME PARAMETERS
CONTENTS
#+END:

NAME 不能包含任何空格字符。

PARAMETERS 可以包含任何字符,可以省略。

3.4 Footnote Definitions

Footnote definition 的模式是:

[LABEL] CONTENTS

它必须从列0开始。

LABEL 是一个数字或遵循 fn:WORD 的模式,其中word可以包含任何字组字符(word-constituent character),连字符和下划线字符。

CONTENTS 可以包含除另一个 Footnote definition 定义之外的任何元素。 它在下一个脚注定义结束,下一个标题,两个连续的空行或缓冲区的结尾。

3.5 Inlinetasks

Inlinetasks 定义为从第0列开始的 org-inlinetask-min-level 个连续星号字符,后跟空格字符。

可选地,可以使用由从第0列开始的 org-inlinetask-min-level 个连续星号字符构成的字符串来结束 Inlinetasks ,后面跟着空格和"END"字符串。

只有在加载了 org-inlinetask 库之后才能识别 Inlinetasks 。

3.6 Plain Lists and Items

Item 通过从以下模式开始的行来定义:

BULLET COUNTER-SET CHECK-BOX TAG

其中只有BULLET是必须的。

BULLET 是星号,连字符,加号(用于 unstored list)或者遵循模式 COUNTER. 或者 COUNTER) (用于 stored list)。 在任何情况下,BULLET后跟空格字符或换行符。

COUNTER 可以是数字或单个字母。

COUNTER-SET 遵循模式[@COUNTER]。

CHECK-BOX 是单个空格字符, X 字符或连字符,括在方括号中。

TAG 遵循 "TAG-TEXT ::"模式,其中TAG-TEXT可以包含除换行符以外的任意字符。

Item 在下一个 Item 之前结束条件: 小于或等于其起始行缩进的首行,或两个连续的空行。 其他 Greater elements 内的线的缩进不算,内联边界也不计。

Plain list 是一组具有相同缩进的连续 Item 。 它只能直接包含 Item 。

如果 Plain list 中的第一个 Item 在其 bullet 中有一个 counter ,那么 Plain list 将是一个 ordered plain-list 。 如果它包含一个 tag ,它将是一个 descriptive list 。 否则,它将是一个 unordered list 。 List 类型是互斥的。

示例,思考如下的Org文档片段:

1. item 1
2. [X] item 2
   - some tag :: item 2.1

它的内部结构如下所示:

(ordered-plain-list
 (item)
 (item
  (descriptive-plain-list
   (item))))

3.7 Property Drawers

Property Drawer 是一种特殊类型的 Drawer ,包含附加到标题的属性。 它们位于headline 和其planning信息之后。

HEADLINE
PROPERTYDRAWER

HEADLINE
PLANNING
PROPERTYDRAWER

PROPERTYDRAWER 遵循下面的模式

:PROPERTIES:
CONTENTS
:END:

其中 CONTENTS 由零个或多个node properties组成。

3.8 Tables

Tables 从以竖线或"+-"字符串开始的行开始,后面跟着加号或减号,假定它们前面没有相同类型的行。 这些线可以缩进。

以垂直条开始的表具有 org 类型。 否则它具有 table.el 类型。

Org Tables 结束于以竖线开始的行。 Table.el Tables 结束于不以垂直线或加号开始的行。 这样的线可以是锯齿状的。

Org Tables 只能包含 table rows 。 table.el Tables 不包含任何内容。

一个或多个"#+TBLFM:FORMULAS"行,其中 FORMULAS 可以包含任何字符,可以在 Org Tables 之后。

4 Elements

Element 不能包含任何其他元素。

只有keywords名称属于 org-element-document-properties, verse blocks , paragraphs 和 table rows 可以包含 Object 。

4.1 Babel Call

Babel calls 的模式如下:

#+CALL: VALUE

VALUE 是可选的。 它可以包含除换行符以外的任意字符。

4.2 Blocks

像 Greater blocks 一样, Block 模式如下:

#+BEGIN_NAME DATA
CONTENTS
#+END_NAME

NAME 不能包含任何空格字符。

如果 NAME 是 COMMENT ,它将是一个"comment block"。如果它是 EXAMPLE ,它将是一个"example block"。 如果它是 EXPORT ,它将是一个"export block"。如果它是 SRC ,它将是一个"source block"。如果是 VERSE ,它将是一个"verse block"。

如果 NAME 是与加载的任何 export back-end 的名称相匹配,则块将是"export block"。

DATA 可以包含除换行符以外的任意字符。它可以省略,除非 Block 是"source block"或"export block"。 在后一种情况(export block)下,它应该由一个单词组成。 在前一种情况(source block)下,它必须遵循"LANGUAGE SWITCHES ARGUMENTS"的模式,其中 SWITCHES 和 ARGUMENTS 是可选的。

LANGUAGE 不能包含任何空格字符。

SWITCHES 由任意数量的"SWITCH"模式组成,由空行分隔。

SWITCH 模式是 "-l" FORMAT "",其中 FORMAT 可以包含除双引号和换行符之外的任意字符, "-S"或"+ S",其中S表示单个字母。

ARGUMENTS 可以包含除换行符以外的任意字符。

CONTENTS 可以包含任意字符, 包括换行符。 Verse block 只能包含 Org Block ,不然的话 CONTENTS 将不能被解析。

4.3 Clock, Diary Sexp and Planning

Clock 模式如下:

CLOCK: TIMESTAMP DURATION

TIMESTAMP 和 DURATION 都是可选的。

TIMESTAMP 是一个 timestamp object 。

DURATION 遵循模式如下:

=> HH:MM

HH是一个包含任意位数的数字。 MM是两位数字。

Diary sexp 是以第"%%("从0列起始一行,它可以包含除了换行符之外的任意字符。

planning 遵循下面模式的 Element :

HEADLINE
PLANNING

其中 HEADLINE 是标题 Element ,PLANNING是填充有INFO部分的行,其中每个都遵循以下模式:

KEYWORD: TIMESTAMP

KEYWORD是 org-deadline-string , org-scheduled-string 和 org-closed-string 中的一个字符串。 TIMESTAMP是一个timestamp Object 。 特别要强调的一点,就是在PLANNING和HEADLINE之间不允许有空行。

即使 Planning element 可以存在于一个 Section 中的任何地方或者一个 Greater element 中,但是它只影响标题包含的 Section ,前提是它位在该标题之后。

4.4 Comments

A "comment line" starts with a hash signe and a whitespace character or an end of line.

Comments can contain any number of consecutive comment lines.

4.5 Fixed Width Areas

A "fixed-width line" start with a colon character and a whitespace or an end of line.

Fixed width areas can contain any number of consecutive fixed-width lines.

4.6 Horizontal Rules

A horizontal rule is a line made of at least 5 consecutive hyphens. It can be indented.

4.7 Keywords

Keywords 语法如下:

#+KEY: VALUE

KEY 可以包含任何非空字符,但不能等于"CALL"或任何 Affiliated keyword 。

VALUE 可以包含除了换行符之外的任何字符。

如果 KEY 属于 org-element-document-properties ,则 VALUE 可以包含 Object 。

4.8 LaTeX Environments

LaTeX environment 的模式如下:


\begin{NAME}ARGUMENTS
CONTENTS
\end{NAME}

NAME 由字母数字或星号字符组成。

CONTENTS 可以包含除"\ end {NAME}"字符串之外的任何内容。

NAME is constituted of alpha-numeric characters and may end with an asterisk.

ARGUMENTS is is any number (including zero) of ARGUMENT constructs like [DATA] or {DATA} . DATA can contain any character excepted a new line or the one ending ARGUMENT.

CONTENTS can contain anything but the "\end{NAME}" string.

4.9 Node Properties

Node propertie 只能存在于property drawers中。 它可以是下面模式的任意一个:

:NAME: VALUE

:NAME+: VALUE

:NAME:

:NAME+:

NAME* 可以包含任何非空字符,但不能以加号结尾。 不能是空字符串。

VALUE 可以包含除换行符之外的任何内容。

4.10 Paragraphs

Paragraphs 是默认 Element ,这意味着任何无法识别的上下文(unrecognized context)都是段落。

空行和其他 Element 结束 Paragraphs 。

Paragraphs 可以包含任意类型的 Object 。

4.11 Table Rows

Table Row 由 vertical bar 和任意数量的table cells组成,或者由连字符后面跟 vertical ba 组成。

在第一种情况下, Tables Row 具有 standard 类型。 在第二种情况下,它具有 rule 类型。

Tables Row 只能存在于tables中。

A table rows is either constituted of a vertical bar and any number of table cells or a vertical bar followed by a hyphen.

In the first case the table row has the "standard" type. In the second case, it has the "rule" type.

Table rows can only exist in tables.

5 Objects

只能在以下位置找到 Object:

  • org-element-parsed-keywords 中定义的 affiliated keywords,
  • document properties,
  • headline titles,
  • inlinetask titles,
  • item tags,
  • paragraphs,
  • table cells,
  • table rows, 它只能包含 table cell objects ,
  • verse blocks.

大多数 Object 不能包含 Object 。 那些可以包含的会做特别说明的。

5.1 Entities and LaTeX Fragments

Entities 遵循的模式如下:

\NAME POST

其中 NAME 和 org-entities 或 org-entities-user 之间具有有效关联。

POST 是行尾,"{}""字符串或非字母字符。 它不是由空格符与NAME分隔。 where NAME has a valid association in either org-entities or org-entities-user.

LaTeX Fragments 可以遵循多种模式:

\NAME BRACKETS
\(CONTENTS\)
\[CONTENTS\]
$$CONTENTS$$
PRE$CHAR$POST
PRE$BORDER1 BODY BORDER2$POST

NAME 仅包含字母字符,且不能和 org-entities 或 org-entities-user 具有关联。

BRACKETS 是可选的,不与 NAME 用空格分隔。 它可以包含任意数量的以下模式:


[CONTENTS1]
{CONTENTS2}

其中CONTENTS1可以包含除"{""}","[""]"以及换行符和CONTENTS2之外的任何字符可以包含除"{","}"和换行符之外的任何字符。

CONTENTS can contain any character but cannot contain "\)" in the second template or "\]" in the third one.

PRE is either the beginning of line or a character different from $.

CHAR is a non-whitespace character different from ., ~,~, ?, ;, ~'~ or a double quote.

POST is any of -, ., ~,~, ?, ;, :, ~'~, a double quote, a whitespace character and the end of line.

BORDER1 is a non-whitespace character different from ., ;, . and $.

BODY can contain any character excepted $, and may not span over more than 3 lines.

BORDER2 is any non-whitespace character different from ~,~, . and $.


It would introduce incompatibilities with previous Org versions, but support for $...$ (and for symmetry, $$...$$) constructs ought to be removed.

They are slow to parse, fragile, redundant and imply false positives. — ngz

5.2 Export Snippets

Export snippets 模式如下:

@@NAME:VALUE@@

NAME 可以包含任何字母数字字符和连字符。

VALUE 可以包含除"@@"字符串之外的任何内容。

5.3 Footnote References

Footnote References 有四种模式:

[MARK]
[fn:LABEL]
[fn:LABEL:DEFINITION]
[fn::DEFINITION]

MARK 是一个数字。

LABEL 可以包含任何字组成字符,连字符和下划线。

DEFINITION 可以包含任何字符。 开关方括号必须成对出现。 它可以包含任何出现在 Paragraph 中的 Object ,甚至其他 Footnote Reference 。

如果引用遵循第三模式,则其被称为 inline footnote ,如果它跟随第四个,即如果省略 LABEL ,它是一个 anonymous footnote 。

5.4 Inline Babel Calls and Source Blocks

Inline Babel call 遵循以下任何模式:

call_NAME(ARGUMENTS)
call_NAME[HEADER](ARGUMENTS)[HEADER]

NAME can contain any character besides (, ) and "\n".

HEADER can contain any character besides ] and "\n".

ARGUMENTS can contain any character besides ) and "\n".

Inline source blocks 遵循以下任何模式:


src_LANG{BODY}
src_LANG[OPTIONS]{BODY}

LANG can contain any non-whitespace character.

OPTIONS and BODY can contain any character but "\n".

5.5 Line Breaks

A line break consists in "\\SPACE" pattern at the end of an otherwise non-empty line.

SPACE can contain any number of tabs and spaces, including 0.

5.6 Links

有4种主要类型的 Link:

PRE1 RADIO POST1          ("radio" link)
<PROTOCOL:PATH>           ("angle" link)
PRE2 PROTOCOL:PATH2 POST2 ("plain" link)
[[PATH3]DESCRIPTION]      ("regular" link)

PRE1 和 POST1 (如果存在)是非字母数字字符。

RADIO 是被某些radio target 匹配的字符串。 它可以只包含 entities, latex fragments, subscript 和 superscript。

PROTOCOL 属于 org-link-types 中定义的链接协议类型。

PATH 可以包含除了 ], <, > 和 \n 以外的任何字符。

PRE2 和 POST2 ,当它们存在时,是非字构成字符(word constituent characters)。

PATH2 可以包含除了 (, ), < 和 > 之外的任何非空字符。 它必须以字组成字符结尾,或任何非空格 非标点符号后面跟着 / 。

DESCRIPTION 必须括在方括号中。 它可以包含除了方括号以外的任何字符。 它可以包含除了 footnote reference, radio target 和 line break之外的任何可在 paragraph 中找到的 object 。 它不能包含另一个 link ,除非它是 plain 或者 angular link 。

DESCRIPTION 是可选的。

PATH3 根据以下模式构建:

FILENAME           ("file" type)
PROTOCOL:PATH4     ("PROTOCOL" type)
PROTOCOL://PATH4   ("PROTOCOL" type)
id:ID              ("id" type)
#CUSTOM-ID         ("custom-id" type)
(CODEREF)          ("coderef" type)
FUZZY              ("fuzzy" type)

FILENAME 是一个文件名,绝对路径或相对路径。

PATH4 可以包含除方括号外的任何字符。

ID 由用连字符分隔的十六进制数字构成。

PATH4 ,*CUSTOM-ID* ,*CODEREF* 和 FUZZY 可以包含除方括号外的任何字符。


I suggest to remove angle links. If one needs spaces in PATH, she can use standard link syntax instead.

I also suggest to remove org-link-types dependency in PROTOCOL and match [a-zA-Z] instead, for portability. — ngz

5.7 Macros

Macros 遵循如下模式:


{{{NAME(ARGUMENTS)}}}

NAME 必须以字母开头,后面可以跟随任意数量的字母数字字符,连字符和下划线。

ARGUMENTS 可以包含除"}}}" 字符串之外的任何内容。 ARGUMENTS 中的值用逗号分隔。 非分隔逗号必须用反斜杠字符转义。

5.8 Targets and Radio Targets

Radio targets 的模式如下:

<<<CONTENTS>>>

CONTENTS 可以是除了 <, > 和 \n 之外的任何字符。 它不能以空格字符开始或结束。 作为 objects 而言,它只可以包含 entities, latex fragments, subscript 和 superscript。

Targets 的模式如下:

<<TARGET>>

TARGET 可以是除了 <, > 和 \n 之外的任何字符。 不能包含任何 Objects .

5.9 Statistics Cookies

Statistics cookies 遵循任一模式:

[PERCENT%]
[NUM1/NUM2]

PERCENT ,*NUM1* 和 NUM2 是数字或空字符串。

5.10 Subscript and Superscript

Subscript 的模式是:

CHAR_SCRIPT

Superscript 的模式是:

CHAR^SCRIPT

CHAR 是任何非空格字符。

SCRIPT 可以是 * 或括在括号(respectively curly brackets)中的表达式,可能包含平衡括号(respectively curly brackets)。

SCRIPT循该如下模式:

SIGN CHARS FINAL

SIGN 是加号,减号或空字符串。

CHARS 是任意数量的字母数字字符,逗号,反斜杠和点,或空字符串。

FINAL 是一个字母数字字符。

SIGN ,*CHARS* 和 FINAL 之间没有空格。

5.11 Table Cells

Table cells 遵循如下模式:

CONTENTS SPACES|

CONTENTS可以包含除垂直条之外的任何字符。

SPACES包含任意数量的空格字符,包括零。 它可用于正确对齐表格。

最后一个条可以用行中最后一个单元格的换行符替换。

5.12 Timestamps

Timestamp 有七种可能的模式:

<%%(SEXP)>                                   (diary)
<DATE TIME REPEATER-OR-DELAY>                                  (active)
[DATE TIME REPEATER-OR-DELAY]                                  (inactive)
<DATE TIME REPEATER-OR-DELAY>--<DATE TIME REPEATER-OR-DELAY>   (active range)
<DATE TIME-TIME REPEATER-OR-DELAY>                             (active range)
[DATE TIME REPEATER-OR-DELAY]--[DATE TIME REPEATER-OR-DELAY]   (inactive range)
[DATE TIME-TIME REPEATER-OR-DELAY]                             (inactive range)

SEXP 可以包含除了 > 和 \n 之外任何字符。

DATE 模式如下:

YYYY-MM-DD DAYNAME

Y ,*M* 和 D 是数字。 DAYNAME可以包含除 +, -, ], >, 数字 和 \n 之外的任何非空白字符。

TIME 遵循模式= H:MM〜。 H可以是一个或两个数字长,可以从0开始。

REPEATER 模式如下:

MARK VALUE UNIT

MARK 对于 repeater 而言,是 + (cumulate type), ++ (catch-up type) 或者 .+ (restart type) 。 在 warning delays 的请求, MARK 可以是 - (all type) 或者 -- (first type)。

VALUE 是一个数字。

UNIT 是h(小时),d(日),w(周),m(月),y(年)中的字符。

MARK ,*VALUE* 和 UNIT 不以空格字符分隔。

时间戳中可以有两个REPEATER-OR-DELAY:一个作为 repeater ,一个作为 warning delays 。

5.13 Text Markup

Text markup 模式如下:

PRE MARKER CONTENTS MARKER POST

PRE 是一个空格字符, (, { ~'~ 或一个双引号,它也可以是一行的开头。

MARKER 是 * (bold), = (verbatim), / (italic), + (strike-through), _ (underline), ~ (code) 中的符号。

CONTENTS 是模式如下的字符串:

BORDER BODY BORDER

BORDER 可以是除了 ~,~, ~'~ 和双引号之外的任何非空格字符。

BODY 可以包含任何字符,但不能跨越超过3行。

BORDER 和 BODY 不被空格分隔。

当标记为 "bold", "italic", "strike-through" 或者 "underline"时, CONTENTS 可以包含段落中遇到的任何对象。

POST是一个空格字符, -, ., ~,~, :, !, ?, ~'~, ), } 或双引号。 它也可以是行尾。

PRE , MARKER , CONTENTS ,*MARKER* 和 POST 不以空格字符分隔。


All of this is wrong if org-emphasis-regexp-components or org-emphasis-alist are modified.

This should really be simplified and made persistent (i.e. no defcustom allowed). Otherwise, portability and parsing are jokes.

Also, CONTENTS should be anything within code and verbatim emphasis, by definition. — ngz

脚注:

1

Org Syntax (draft) 的org源码: http://orgmode.org/worg/sources/dev/org-syntax.org

因此,使用 org-element-at-point 或 org-element-context 将向上移动到父标题,并从那里自顶向下解析,直到找到原始位置周围的上下文。

2

特别说明,解析器要求在列0处的星号在不被定义为标题时用逗号来引用。

3

这也意味着只有 Headline 和 Section 能通过查看行的开头来识别。 Planning lines 和 Property drawers 可以通过查看一行或两行以上来识别。

Last Updated 2017-05-23 Tue 13:28.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)

Hello World

发表于 2017-03-07 | 分类于 hexo |

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

1…34
Brantou

Brantou

39 日志
5 分类
46 标签
RSS
GitHub Twitter E-Mail Jianshu
© 2017 — 2018 Brantou
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.3
Hosted by GitHub Pages