v1.0.0
发布于 2015 年 2 月 12 日 – 文本版本

TOML v0.4.0

Tom 的明显最小语言。

作者:Tom Preston-Werner。

注意,此规范仍在发生很多变化。在标记为 1.0 之前,您应该假设它是不稳定的,并据此采取行动。

目标

TOML 旨在成为一种最小的配置文件格式,由于其明显的语义,易于阅读。TOML 旨在无歧义地映射到哈希表。TOML 应该易于解析为各种语言中的数据结构。

规范

  • TOML 区分大小写。
  • TOML 文件必须仅包含 UTF-8 编码的 Unicode 字符。
  • 空格表示制表符 (0x09) 或空格 (0x20)。
  • 换行符表示 LF (0x0A) 或 CRLF (0x0D0A)。

注释

使用井号表达你的想法。它们从符号到行尾。

# I am a comment. Hear me roar. Roar.
key = "value" # Yeah, you can do this.

字符串

有四种方法可以表达字符串:基本字符串、多行基本字符串、字面字符串和多行字面字符串。所有字符串都必须仅包含有效的 UTF-8 字符。

**基本字符串**用双引号括起来。可以使用任何 Unicode 字符,除了必须转义的字符:双引号、反斜杠和控制字符 (U+0000 到 U+001F)。

"I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."

为方便起见,一些常用字符具有紧凑的转义序列。

\b         - backspace       (U+0008)
\t         - tab             (U+0009)
\n         - linefeed        (U+000A)
\f         - form feed       (U+000C)
\r         - carriage return (U+000D)
\"         - quote           (U+0022)
\\         - backslash       (U+005C)
\uXXXX     - unicode         (U+XXXX)
\UXXXXXXXX - unicode         (U+XXXXXXXX)

任何 Unicode 字符都可以使用\uXXXX\UXXXXXXXX形式进行转义。转义代码必须是有效的 Unicode 标量值

上面未列出的所有其他转义序列均为保留,如果使用,TOML 应产生错误。

有时您需要表达文本段落(例如翻译文件)或希望将很长的字符串分解成多行。TOML 使这变得容易。**多行基本字符串**两侧用三个双引号括起来,并允许换行符。紧跟在起始分隔符之后的换行符将被修剪。所有其他空格和换行符字符保持不变。

key1 = """
Roses are red
Violets are blue"""

TOML 解析器可以自由地将换行符规范化为其平台上任何有意义的内容。

# On a Unix system, the above multi-line string will most likely be the same as:
key2 = "Roses are red\nViolets are blue"

# On a Windows system, it will most likely be equivalent to:
key3 = "Roses are red\r\nViolets are blue"

为了编写长字符串而不引入多余的空格,请在行尾使用\\将与所有空格(包括换行符)一起被修剪,直到下一个非空格字符或结束分隔符。如果起始分隔符后的第一个字符是反斜杠和换行符,则它们都将与所有空格和换行符一起被修剪,直到下一个非空格字符或结束分隔符。所有对基本字符串有效的转义序列也对多行基本字符串有效。

# The following strings are byte-for-byte equivalent:
key1 = "The quick brown fox jumps over the lazy dog."

key2 = """
The quick brown \


  fox jumps over \
    the lazy dog."""

key3 = """\
       The quick brown \
       fox jumps over \
       the lazy dog.\
       """

可以使用任何 Unicode 字符,除了必须转义的字符:反斜杠和控制字符 (U+0000 到 U+001F)。引号无需转义,除非它们的存在会导致过早的结束分隔符。

如果您经常指定 Windows 路径或正则表达式,那么必须转义反斜杠很快就会变得乏味且容易出错。为了提供帮助,TOML 支持字面字符串,其中根本不允许转义。**字面字符串**用单引号括起来。与基本字符串一样,它们必须出现在一行上。

# What you see is what you get.
winpath  = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
quoted   = 'Tom "Dubs" Preston-Werner'
regex    = '<\i\c*\s*>'

由于没有转义,因此无法在用单引号括起来的字面字符串中写入单引号。幸运的是,TOML 支持字面字符串的多行版本,该版本解决了此问题。**多行字面字符串**两侧用三个单引号括起来,并允许换行符。与字面字符串一样,没有任何转义。紧跟在起始分隔符之后的换行符将被修剪。分隔符之间的所有其他内容都按原样解释,无需修改。

regex2 = '''I [dw]on't need \d{2} apples'''
lines  = '''
The first newline is
trimmed in raw strings.
   All other whitespace
   is preserved.
'''

对于二进制数据,建议您使用 Base64 或其他合适的 ASCII 或 UTF-8 编码。该编码的处理方式将是特定于应用程序的。

整数

整数是整数。正数可以以加号为前缀。负数以减号为前缀。

+99
42
0
-17

对于大数字,您可以使用下划线来增强可读性。每个下划线必须至少由一个数字包围。

1_000
5_349_221
1_2_3_4_5     # valid but inadvisable

不允许前导零。不允许使用十六进制、八进制和二进制形式。诸如“无穷大”和“非数字”等无法表示为一系列数字的值不允许。

预期为 64 位(有符号长整型)范围(-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807)。

浮点数

浮点数由整数部分(可以以加号或减号为前缀)后跟小数部分和/或指数部分组成。如果同时存在小数部分和指数部分,则小数部分必须位于指数部分之前。

# fractional
+1.0
3.1415
-0.01

# exponent
5e+22
1e6
-2E-2

# both
6.626e-34

小数部分是小数点后跟一个或多个数字。

指数部分是 E(大写或小写)后跟整数部分(可以以加号或减号为前缀)。

与整数类似,您可以使用下划线来增强可读性。每个下划线必须至少由一个数字包围。

9_224_617.445_991_228_313
1e1_000

预期为 64 位(双精度)精度。

布尔值

布尔值只是您习惯使用的标记。始终小写。

true
false

日期时间

日期时间是 RFC 3339 日期。

1979-05-27T07:32:00Z
1979-05-27T00:32:00-07:00
1979-05-27T00:32:00.999999-07:00

数组

数组是用方括号括起来的包含其他基元。空格将被忽略。元素用逗号分隔。数据类型不能混合(尽管所有字符串类型都应被视为同一类型)。

[ 1, 2, 3 ]
[ "red", "yellow", "green" ]
[ [ 1, 2 ], [3, 4, 5] ]
[ "all", 'strings', """are the same""", '''type'''] # this is ok
[ [ 1, 2 ], ["a", "b", "c"] ] # this is ok
[ 1, 2.0 ] # note: this is NOT ok

数组也可以是多行的。因此,除了忽略空格之外,数组还忽略方括号之间的换行符。在结束括号之前允许使用结尾逗号。

key = [
  1, 2, 3
]

key = [
  1,
  2, # this is ok
]

表(也称为哈希表或字典)是键/值对的集合。它们单独出现在一行上的方括号中。您可以将它们与数组区分开来,因为数组永远只是值。

[table]

在它下面,直到下一个表或文件结尾,都是该表的键/值。键位于等号的左侧,值位于右侧。键名和值周围的空格将被忽略。键、等号和值必须在同一行上(尽管某些值可以跨多行)。

键可以是裸键或带引号的键。**裸键**只能包含字母、数字、下划线和连字符(A-Za-z0-9_-)。**带引号的键**遵循与基本字符串完全相同的规则,并允许您使用更广泛的键名集。最佳实践是使用裸键,除非绝对必要。

表中的键/值对不保证按任何特定顺序排列。

[table]
key = "value"
bare_key = "value"
bare-key = "value"

"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"

裸键中禁止使用点,因为点用于表示嵌套表!每个点分隔部分的命名规则与键相同(请参见上文)。

[dog."tater.man"]
type = "pug"

在 JSON 中,将为您提供以下结构

{ "dog": { "tater.man": { "type": "pug" } } }

点分隔部分周围的空格将被忽略,但是,最佳实践是不使用任何多余的空格。

[a.b.c]          # this is best practice
[ d.e.f ]        # same as [d.e.f]
[ g .  h  . i ]  # same as [g.h.i]
[ j . "ʞ" . l ]  # same as [j."ʞ".l]

如果您不想指定所有超级表,则不必指定。TOML 知道如何为您做到这一点。

# [x] you
# [x.y] don't
# [x.y.z] need these
[x.y.z.w] # for this to work

允许使用空表,并且它们根本没有键/值对。

只要超级表尚未直接定义且尚未定义特定键,您仍然可以写入它。

[a.b]
c = 1

[a]
d = 2

您不能多次定义任何键或表。这样做是无效的。

# DO NOT DO THIS

[a]
b = 1

[a]
c = 2
# DO NOT DO THIS EITHER

[a]
b = 1

[a.b]
c = 2

所有表名和键都必须是非空的。

# NOT VALID TOML
[]
[a.]
[a..b]
[.b]
[.]
 = "no key name" # not allowed

内联表

内联表提供了一种更紧凑的语法来表达表。它们对于可以快速变得冗长的分组数据特别有用。内联表用花括号{}括起来。在大括号内,可以出现零个或多个用逗号分隔的键/值对。键/值对采用与标准表中的键/值对相同的形式。所有值类型都允许,包括内联表。

内联表旨在出现在一行上。在大括号之间不允许换行符,除非它们在值中有效。即便如此,也强烈建议不要将内联表拆分到多行上。如果您发现自己渴望这样做,这意味着您应该使用标准表。

name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }

上面的内联表与以下标准表定义相同

[name]
first = "Tom"
last = "Preston-Werner"

[point]
x = 1
y = 2

表数组

尚未表达的最后一种类型是表数组。这些可以通过在表名中使用双括号来表达。每个具有相同双括号名称的表都将是数组中的一个元素。表按遇到的顺序插入。没有键/值对的双括号表将被视为空表。

[[products]]
name = "Hammer"
sku = 738594937

[[products]]

[[products]]
name = "Nail"
sku = 284758393
color = "gray"

在 JSON 中,将为您提供以下结构。

{
  "products": [
    { "name": "Hammer", "sku": 738594937 },
    { },
    { "name": "Nail", "sku": 284758393, "color": "gray" }
  ]
}

您也可以创建嵌套的表数组。只需在子表上使用相同的双括号语法即可。每个双括号子表都将属于上面最近定义的表元素。

[[fruit]]
  name = "apple"

  [fruit.physical]
    color = "red"
    shape = "round"

  [[fruit.variety]]
    name = "red delicious"

  [[fruit.variety]]
    name = "granny smith"

[[fruit]]
  name = "banana"

  [[fruit.variety]]
    name = "plantain"

上面的 TOML 映射到以下 JSON。

{
  "fruit": [
    {
      "name": "apple",
      "physical": {
        "color": "red",
        "shape": "round"
      },
      "variety": [
        { "name": "red delicious" },
        { "name": "granny smith" }
      ]
    },
    {
      "name": "banana",
      "variety": [
        { "name": "plantain" }
      ]
    }
  ]
}

尝试定义与已建立数组同名的普通表必须在解析时产生错误。

# INVALID TOML DOC
[[fruit]]
  name = "apple"

  [[fruit.variety]]
    name = "red delicious"

  # This table conflicts with the previous table
  [fruit.variety]
    name = "granny smith"

您也可以在适当的地方使用内联表

points = [ { x = 1, y = 2, z = 3 },
           { x = 7, y = 8, z = 9 },
           { x = 2, y = 4, z = 8 } ]

真的假的?

是的。

为什么?

因为我们需要一种体面的、人类可读的格式,该格式可以无歧义地映射到哈希表,而 YAML 规范却有 80 页长,让我感到愤怒。不,JSON 不算。你知道为什么。

哦天哪,你说得对

是的。想帮忙吗?发送一个拉取请求。或者编写一个解析器。勇敢点。

使用 TOML 的项目

  • Cargo - Rust 语言的包管理器。
  • InfluxDB - 分布式时间序列数据库。
  • Heka - Mozilla 的流处理系统。
  • Hugo - Go 语言编写的静态网站生成器。

实现

如果您有实现,请发送一个拉取请求添加到此列表中。请在您的 Readme 中注意您的解析器支持的提交 SHA1 或版本标签。

验证器

TOML 解码器和编码器的语言无关测试套件

编辑器支持

编码器

转换器