我正在尝试为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中使用不同类型的引号的规则是什么?

是否可以说:

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


当前回答

在简要回顾了问题中引用的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烹饪书并进行了一些测试之后,以下是我的解释:

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'

虽然Mark的回答很好地总结了什么时候根据YAML语言规则需要引号,但我认为,当在YAML中使用字符串时,许多开发人员/管理员会问自己:“我处理字符串的经验法则应该是什么?”

It may sound subjective, but the number of rules you have to remember, if you want to use the quotes only when they are really needed as per the language spec, is somewhat excessive for such a simple thing as specifying one of the most common datatypes. Don't get me wrong, you will eventually remember them when working with YAML regularly, but what if you use it occasionally, and you didn't develop automatism for writing YAML? Do you really want to spend time remembering all the rules just to specify the string correctly?

“经验法则”的全部意义在于节省认知资源,无需思考就能处理一项普通任务。我们的“CPU”时间可以用来做比正确处理字符串更有用的事情。

从这个纯粹实用的角度来看,我认为最好的经验法则是对字符串进行单引号。它背后的原理是:

单引号字符串适用于所有场景,除非需要使用转义序列。 在单引号字符串中必须处理的唯一特殊字符是单引号本身。

对于一些偶尔使用YAML的用户来说,这只是需要记住的2条规则,可以最大限度地减少认知工作量。

下面是一个小函数(没有优化性能),它在需要时用单引号对字符串进行引用,并测试结果是否可以解编组为原始值: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
}
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,你不需要为布尔值使用引号。 只有版本需要报价。

这个问题有一些很好的答案。 然而,我想扩展它们,并提供一些新的官方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规范,我们应该:

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