我正在尝试为Rails项目的国际化编写YAML字典。我有点困惑,因为在一些文件中,我看到字符串在双引号中,而在一些文件中没有。以下几点需要考虑:

example 1 - all strings use double quotes; example 2 - no strings (except the last two) use quotes; the YAML cookbook says: Enclosing strings in double quotes allows you to use escaping to represent ASCII and Unicode characters. Does this mean I need to use double quotes only when I want to escape some characters? If yes - why do they use double quotes everywhere in the first example - only for the sake of unity / stylistic reasons? the last two lines of example 2 use ! - the non-specific tag, while the last two lines of the first example don't - and they both work.

我的问题是:在YAML中使用不同类型的引号的规则是什么?

是否可以说:

一般来说,你不需要引用; 如果你想转义字符,请使用双引号; 使用!用单引号,当…? ! ?


当前回答

version: "3.9"

services:
  seunggabi:
    image: seunggabi:v1.0.0
    command:
      api:
        insecure: true
    ports:
      - 80:80
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
docker compoese up docker-compose.yaml

如果你使用docker compose v2,你不需要为布尔值使用引号。 只有版本需要报价。

其他回答

下面是一个小函数(没有优化性能),它在需要时用单引号对字符串进行引用,并测试结果是否可以解编组为原始值:https://go.dev/play/p/AKBzDpVz9hk。 它不是测试规则,而是简单地使用编组程序本身并检查编组和反编组的值是否与原始版本匹配。

func yamlQuote(value string) string {
    input := fmt.Sprintf("key: %s", value)

    var res struct {
        Value string `yaml:"key"`
    }

    if err := yaml.Unmarshal([]byte(input), &res); err != nil || value != res.Value {
        quoted := strings.ReplaceAll(value, `'`, `''`)
        return fmt.Sprintf("'%s'", quoted)
    }

    return value
}

yaml中的字符串只有在(开头)值可能被误解为数据类型或值包含“:”(因为它可能被误解为键)时才需要引号。

例如

foo: '{{ bar }}'

需要引号,因为它可能被误解为数据类型字典,但是

foo: barbaz{{ bam }}

不是,因为它不是以关键字符开始的。接下来,

foo: '123'

需要引号,因为它可能被误解为数据类型int,但是

foo: bar1baz234
bar: 123baz

不是,因为它不能被误解为int

foo: 'yes'

需要引号,因为它可能被误解为datatype bool

foo: "bar:baz:bam"

需要引号,因为该值可能被误解为键。

这些只是例子。使用yamllint有助于避免使用错误的令牌开始值

foo@bar:/tmp$ yamllint test.yaml 
test.yaml
  3:4       error    syntax error: found character '@' that cannot start any token (syntax)

并且是必须的,如果与yaml有效地工作。

像一些人建议的那样引用所有字符串,就像在python中使用括号一样。这是一种糟糕的做法,损害了可读性,并抛弃了不必引用字符串的美妙特性。

在简要回顾了问题中引用的YAML烹饪书并进行了一些测试之后,以下是我的解释:

In general, you don't need quotes. Use quotes to force a string, e.g. if your key or value is 10 but you want it to return a String and not a Fixnum, write '10' or "10". Use quotes if your value includes special characters, (e.g. :, {, }, [, ], ,, &, *, #, ?, |, -, <, >, =, !, %, @, \). Single quotes let you put almost any character in your string, and won't try to parse escape codes. '\n' would be returned as the string \n. Double quotes parse escape codes. "\n" would be returned as a line feed character. The exclamation mark introduces a method, e.g. !ruby/sym to return a Ruby symbol.

在我看来,最好的方法是除非必要,否则不要使用引号,然后使用单引号,除非特别想处理转义码。

更新

“Yes”和“No”应该用双引号括起来(单引号或双引号),否则它们将被解释为TrueClass和FalseClass值:

en:
  yesno:
    'yes': 'Yes'
    'no': 'No'

这个问题有一些很好的答案。 然而,我想扩展它们,并提供一些新的官方YAML v1.2.2规范(2021年10月1日发布)的背景,这是所有考虑YAML的“真正来源”。

有三种不同的风格可以用来表示字符串,每一种都有自己的(缺点)优点:

YAML提供了三种流标量样式:双引号、单引号和普通(不加引号)。每一种都在可读性和表现力之间提供了不同的权衡。

双引号风格:

双引号样式由周围的“indicators”指定。这是唯一能够通过使用\转义序列来表示任意字符串的样式。这是以必须转义\和"字符为代价的。

使用单引号风格:

单引号样式由周围的“指示器”指定。因此,在单引号标量中,这样的字符需要重复。这是在单引号标量中执行转义的唯一形式。特别是\和"字符可以自由使用。这将单引号标量限制为可打印字符。此外,只有在空格字符被非空格包围的长单引号行中才有可能换行。

朴素(未引用)风格:

The plain (unquoted) style has no identifying indicators and provides no form of escaping. It is therefore the most readable, most limited and most context sensitive style. In addition to a restricted character set, a plain scalar must not be empty or contain leading or trailing white space characters. It is only possible to break a long plain line where a space character is surrounded by non-spaces. Plain scalars must not begin with most indicators, as this would cause ambiguity with other YAML constructs. However, the :, ? and - indicators may be used as the first character if followed by a non-space “safe” character, as this causes no ambiguity.

博士TL;

话虽如此,根据官方YAML规范,我们应该:

只要适用,就使用不加引号的样式,因为它是最易读的。 如果字符串中使用了"和\这样的字符,则使用单引号样式('),以避免转义,从而提高可读性。 当前两个选项不充分时,例如在需要更复杂的换行符或需要不可打印字符的情况下,使用双引号样式(")。

version: "3.9"

services:
  seunggabi:
    image: seunggabi:v1.0.0
    command:
      api:
        insecure: true
    ports:
      - 80:80
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
docker compoese up docker-compose.yaml

如果你使用docker compose v2,你不需要为布尔值使用引号。 只有版本需要报价。