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

是否可以说:

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


当前回答

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

其他回答

虽然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条规则,可以最大限度地减少认知工作量。

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中使用括号一样。这是一种糟糕的做法,损害了可读性,并抛弃了不必引用字符串的美妙特性。

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
}

在使用Docker开发Rails应用程序时,我就有这个顾虑。

我最喜欢的方法是一般不使用引号。这包括不使用引号:

比如${RAILS_ENV} 用冒号(:)分隔的值,如postgresql -log:/var/log/postgresql 其他字符串值

然而,对于需要转换为字符串的整数值,我使用双引号:

Docker-compose类似版本:"3.8" 端口号如“8080:8080” 形象”traefik: v2.2.1”

但是,对于特殊情况,如布尔值、浮点数、整数和其他情况,在其中使用双引号的条目值可能被解释为字符串,请不要使用双引号。

下面是一个docker-compose示例。Yml文件来解释这个概念:

version: "3"

services:
  traefik:
    image: "traefik:v2.2.1"
    command:
      - --api.insecure=true # Don't do that in production
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

这是所有。

我希望这对你们有帮助