如何在YAML中将字符串分成多行?

2607

我有一个非常长的字符串:

Key: 'this is my very very very very very very long string'

我想将它分成多行,例如:

Key: 'this is my very very very ' +
     'long string'

我想使用上述引号,这样我就不需要在字符串内转义任何内容。

5
小贴士:无法在标量内部添加注释,因此无法对多行键或值的部分进行注释。必须将需要注释的行移到声明之外。https://dev59.com/jWEi5IYBdhLWcg3w2fUm - gavenkoa
请使用此参考链接:https://yaml-multiline.info/ - Ed Randall
9个回答

5728

在YAML中,有5个、6个或者9个(根据计算方式而定)不同的方法来编写多行字符串。

简而言之

  • 大部分时间使用>:内部换行会被去除,但是最后会有一个换行:

      key: >
        这里是你的
        长字符串。
    
  • 如果你希望保留这些换行作为\n(例如,带有段落的嵌入式Markdown),请使用|

      key: |
        ### 标题
    
        * 项目
        * 
    
  • 如果你不想在末尾添加换行,请使用>-|-

  • 如果你需要在单词中间分割行或者想要直接输入\n作为换行,请使用"..."

      key: "Antidisestab\
       lishmentarianism.\n\n开始吧。"
    
  • YAML太疯狂了。

块标量样式(>|)允许使用\"等字符而无需转义,并在字符串末尾添加一个新行(\n)。 > 折叠样式会移除字符串中的单个换行符(但在末尾添加一个换行符,并将双重换行符转换为单个换行符):
Key: >
  this is my very very very
  long string

这是我的非常非常非常长的字符串\n

额外的前导空格被保留并导致额外的换行符。请参见下面的说明。

建议:使用这个。通常这是你想要的。

| 文字样式 将字符串中的每个换行符转换为实际的换行符,并在末尾添加一个:

Key: |
  this is my very very very 
  long string

这是我的非常非常非常长的字符串

这是来自YAML规范1.2的官方定义

标量内容可以使用块注释写入,使用文字样式(由“|”表示),其中所有换行都是有意义的。或者,它们可以使用折叠样式(由“>”表示),其中每个换行都折叠为一个空格,除非它结束一个空行或更高缩进的行。

建议:将格式化文本(特别是Markdown)作为值插入。

带有块换行指示符(>-|->+|+)的块样式

您可以通过添加块换行指示符字符来控制字符串中最后一个换行符和任何尾随的空行(\n\n)的处理方式:

  • >|:clip:保留换行符,删除尾部空行。
  • >-|-:strip:删除换行符,删除尾部空行。
  • >+|+:keep:保留换行符,保留尾部空行。

"Flow" 标量样式( "'

这些样式有限的转义,并构造一个没有换行符的单行字符串。它们可以与键在同一行开始,或者在之前有额外的换行符,这些换行符会被删除。双倍的换行符会变成一个换行符。

plain style(无转义,无 #: 组合,第一个字符不能是"'或其他许多标点符号字符):

Key: this is my very very very 
  long string

建议:避免使用。看起来方便,但是如果不小心使用了禁止的标点符号并触发了语法错误,可能会给自己带来麻烦。 双引号样式\"必须通过\进行转义,可以使用字面量\n插入换行,可以使用尾随\将行连接在一起而不需要空格):
Key: "this is my very very \"very\" loooo\
  ng string.\n\nLove, YAML."

"这是我的非常非常“非常”长的字符串。\n\n爱你,YAML。"

建议:只在非常特定的情况下使用。这是唯一的方式,你可以在不添加空格的情况下将非常长的标记(如URL)跨行分隔。而且,在一行中间添加换行符可能是有用的。

单引号样式(字面意义上的'必须加倍,没有特殊字符,可能用于表示以双引号开头的字符串):

Key: 'this is my very very "very"
  long string, isn''t it.'

这是我的非常非常“非常”长的字符串,不是吗。

建议:尽量避免。好处很少,主要是不方便。

带缩进指示符的块样式

如果上述还不够满足您的需求,您可以在块折叠指示符之后添加一个“block indentation indicator”:

- >8
        My long string
        starts over here
- |+1
 This one
 starts here

注意:在折叠样式(>)中,前导空格会被保留。
如果在折叠样式中在非第一行的开头插入额外的空格,它们将被保留,并附带一个换行符。(在流样式中不会发生这种情况。)第6.5节

此外,折叠不适用于包含前导空白的文本行周围的换行符。请注意,这样的更缩进的行可能只包含这样的前导空白。

- >
    my long
      string
                    
    many spaces above
- my long
      string
                    
    many spaces above
    

→ ["我的长\n 字符串\n \n很多空格在上面\n","我的长字符串\n很多空格在上面"]

摘要

在这个表格中:_表示空格字符,\n表示换行字符,除非另有说明。"Leading space"指的是第二行有额外的空格字符,而第一行只有空格(这样就形成了缩进)。

> | >- |- >+ |+ " '
Spaces/newlines converted to:
Trailing space → _ _ _ _ _ _
Leading space → \n_ \n_ \n_ \n_ \n_ \n_
Single newline → _ \n _ \n _ \n _ _ _
Double newline → \n \n\n \n \n\n \n \n\n \n \n \n
Final newline → \n \n \n \n
Final double newline → \n \n \n\n \n\n
How to create a literal:
Single quote ' ' ' ' ' ' ' ' ''
Double quote " " " " " " " \" "
Backslash \ \ \ \ \ \ \ \\ \
Other features
In-line newlines with literal \n
Spaceless newlines with \
# or : in value
Can start on same
line as key

例子

请注意在“spaces”之前一行的尾随空格。

- >
  very "long"
  'string' with

  paragraph gap, \n and        
  spaces.
- | 
  very "long"
  'string' with

  paragraph gap, \n and        
  spaces.
- very "long"
  'string' with

  paragraph gap, \n and        
  spaces.
- "very \"long\"
  'string' with

  paragraph gap, \n and        
  s\
  p\
  a\
  c\
  e\
  s."
- 'very "long"
  ''string'' with

  paragraph gap, \n and        
  spaces.'
- >- 
  very "long"
  'string' with

  paragraph gap, \n and        
  spaces.

[
  "very \"long\" 'string' with\nparagraph gap, \\n and         spaces.\n", 
  "very \"long\"\n'string' with\n\nparagraph gap, \\n and        \nspaces.\n", 
  "very \"long\" 'string' with\nparagraph gap, \\n and spaces.", 
  "very \"long\" 'string' with\nparagraph gap, \n and spaces.", 
  "very \"long\" 'string' with\nparagraph gap, \\n and spaces.", 
  "very \"long\" 'string' with\nparagraph gap, \\n and         spaces."
]

*2个块样式,每个样式有2个可能的块换行指示符(或没有),以及9个可能的缩进指示符(或没有),1个普通样式和2个引用样式:2 x (2 + 1) x (9 + 1) + 1 + 2 = 63

其中一些信息也已在这里进行了总结。


84
在这 63 种语法中,你认为是否有一种语法可以让你在多行中拼写一个不应该包含换行符或空格的字符串?我的意思是像大多数编程语言中的 "..." + "..." 或者 Bash 中的反斜杠加换行符。 - Tobia
42
@pepoluan 我尝试了所有可能的组合,只找到了一种允许无空格连接的方法:在字符串周围加上双引号,在换行符(和缩进)前加上反斜杠。例如:data:text/plain;base64,dGVzdDogImZvb1wKICBiYXIiCg== - Tobia
128
相反,我认为YAML是许多常见用例(例如配置文件)中最糟糕的格式之一,主要是因为大多数人被其表面上的简单性所吸引,只有在很长一段时间后才意识到它是一个非常复杂的格式。 YAML让错误的东西“看起来”正确 - 例如,在字符串数组中的一个字符串中出现的无害冒号“:”会导致YAML将其解释为对象数组。 它违反了“最小惊讶原则”。 - Vicky Chijwani
157
另一种多行字符串语法 - xdhmoore
55
我曾经很难记住 '|' 或 '>' 哪个保留或去除换行符。后来我意识到,如果从左到右阅读运算符,它们告诉你它们如何转换字符串。'|' 两侧高度相同,表示字符串的高度也将保持不变;而 '>' 在右侧比左侧小,表示它将把多行字符串“压缩”为一行。想给那些还没发现这个技巧的人留下这个助记法。 - swenzel
显示剩余18条评论

1427
使用yaml折叠样式。每行中的缩进将被忽略。在末尾插入换行符。
Key: >
  This is a very long sentence
  that spans several lines in the YAML
  but which will be rendered as a string
  with only a single carriage return appended to the end.

http://symfony.com/doc/current/components/yaml/yaml_format.html

您可以使用“块咬合指示器”来消除尾随的换行符,如下所示:
Key: >-
  This is a very long sentence
  that spans several lines in the YAML
  but which will be rendered as a string
  with NO carriage returns.

无论哪种情况,每个换行符都会被替换为一个空格。
还有其他可用的控制工具(例如用于控制缩进)。
请参见https://yaml-multiline.info/

1
谢谢,但你似乎不能将这个语法放在引号中:引号会以字面形式出现在最终字符串中。 - jjkparker
我的应用程序在翻译结束后会自动添加回车符,导致Javascript将其视为多行并失败。即使使用 {{- 'key'|trans -}} 也无法解决。 - Rvanlaak
12
每个换行符将被替换为一个空格,但是两个连续的换行符会被视为一个新行。 - Jean Jordaan
1
@Rvanlaak和@rich-remer,请使用块状切割器避免末尾换行符:>- - DylanYoung
我发现提供的链接 https://yaml-multiline.info 很有用。 - anre
显示剩余3条评论

227

要保留换行符,请使用|,例如:

|
  This is a very long sentence
  that spans several lines in the YAML
  but which will be rendered as a string
  with newlines preserved.

被翻译为"This is a very long sentence‌\n that spans several lines in the YAML‌\n but which will be rendered as a string‌\n with newlines preserved.\n"


这似乎对我来说用两行很好,但用三行就不行了? - cboettig
谢谢,就像你说的那样,它在那里运行得很好。由于某种原因,在Pandoc的yaml头中,我需要在每一行上重复|,这个原因对我来说并不明显:https://groups.google.com/forum/#!topic/pandoc-discuss/xuqEmhWgf9A - cboettig
如果我写下以下代码: - field1: | one two - field1: | three for' 为什么会出现这样的问题:输出结果是 one\ntwo\n 和 three\nfor? 我希望输出结果不要在2后面添加 \n。 - Alain1405
当使用带有分隔符的多行cat时,会导致输出中添加前导空格(这对于YAML是必要的)。 - Kalle Richter
@AliShakiba,你在翻译中漏掉了最后的换行符。如果标量位于文档的根部,则无需缩进其行。 - Anthon
显示剩余3条评论

152

1. 块表示法(普通、流式、标量):换行符变成空格,块后面的额外换行符被删除。

---
# Note: It has 1 new line after the string
content:
    Arbitrary free text
    over multiple lines stopping
    after indentation changes...

...

等效的JSON

{
 "content": "Arbitrary free text over multiple lines stopping after indentation changes..."
}

2. 字面块标量: 字面块标量 | 会包含换行符和任何尾随空格,但会移除块后额外的换行符。

---
# After string we have 2 spaces and 2 new lines
content1: |
 Arbitrary free text
 over "multiple lines" stopping
 after indentation changes...  


...

等效的JSON

{
 "content1": "Arbitrary free text\nover \"multiple lines\" stopping\nafter indentation changes...  \n"
}

3. + indicator with Literal Block Scalar: 保留块后的额外换行符

---
# After string we have 2 new lines
plain: |+
 This unquoted scalar
 spans many lines.


...

等效的 JSON

{
 "plain": "This unquoted scalar\nspans many lines.\n\n\n"
}

4.使用文字块标量的指示器: - 表示字符串末尾的换行符被移除。

---
# After string we have 2 new lines
plain: |-
 This unquoted scalar
 spans many lines.


...

等价的JSON

{
 "plain": "This unquoted scalar\nspans many lines."
}

5. 折叠块标量(>):

将换行符折叠为空格,但会删除块后的多余换行符。

---
folded_newlines: >
 this is really a
 single line of text
 despite appearances


...

等效的JSON

{
 "fold_newlines": "this is really a single line of text despite appearances\n"
}

想要了解更多,您可以访问我的博客


你是否打算在冒号后使用“|-”来完成示例#4?此外,由于您只显示一个文档,因此可以省略“---”指令结束标记。文档结束标记有助于突出文档中的尾随空格。除此之外,没有必要使用显式文档。 - seh
谢谢指出。那是一个打字错误。我已经修复了它。我提供了起始和结束标记,以便每个人都可以在字符串后看到新行。 - Arayan Singh
Nr.1 在 YAML 规范中被描述为普通的流式标量。称其为块状样式是具有误导性的。 - Anthon
将Nr.1变更为纯文本、流式、标量。 - Arayan Singh
此网站无法访问。请检查 interviewbubble.com 是否有拼写错误。DNS_PROBE_FINISHED_NXDOMAIN。谢谢。 - ssi-anik

79

如果要将长行连接 而不使用空格,请使用双引号并使用反斜杠转义新行:

key: "Loremipsumdolorsitamet,consecteturadipiscingelit,seddoeiusmodtemp\
  orincididuntutlaboreetdoloremagnaaliqua."

1
谢谢,这真的帮助我在多行上定义Docker卷!如果有人有同样的问题,这是我的解决方案,使用在线YAML解析器 - Mike Mitterer
啊,终于解决了。我一直在尝试将长的ssh密钥在Puppet的Hiera yaml文件中分多行包装,但总是得到不想要的空格,直到我使用了你的答案。谢谢。 - Martijn Heemels
我正在寻找这个答案。这很愚蠢,因为在yaml中没有选项可以轻松地执行此操作。 - ikhvjs

50

也许你不相信,但 YAML 也可以使用多行键:

?
 >
 multi
 line
 key
:
  value

7
需要解释("?"是什么意思?) - ilyaigpetrov
@ilyaigpetrov,就像原文所写的那样,“multi-line”键。通常你会使用key:value这样的格式,但如果你的键包含换行符,你可以按照上述描述进行操作。 - goFrendiAsgard
8
有没有任何一个现实世界的应用案例可以作为例证? - Richard-Degenne
4
@ilyaigpetrov 中的 ? 是关键指示器(就像映射中的键)。在许多情况下,当 (必需的) 值指示器 : 在键后使解析无歧义时,您可以省略键指示器。但这不是这种情况,您必须使用它来明确标记键。 - Anthon

22
如果您正在使用Symfony中的YAML和Twig进行翻译,并且想要在Javascript中使用多行翻译,那么一个回车符将会在翻译后添加。因此,即使是以下代码:var javascriptVariable = "{{- 'key'|trans -}}";,它所对应的yml翻译也会被添加上一个回车符。
key: >
    This is a
    multi line 
    translation.

仍然会在HTML中产生以下代码:
var javascriptVariable = "This is a multi line translation.
";

因此,Twig中的减号并不能解决这个问题。解决方案是在YML中的大于号后面添加这个减号:
key: >-
    This is a
    multi line 
    translation.

在Twig中,将多行翻译转换为一行,可以得到正确的结果。
var javascriptVariable = "This is a multi line translation.";

这看起来像是一个错误。你有机会提交错误报告吗? - dreftymac

11

对于字符串可能包含空格或不包含空格的情况,我更喜欢使用双引号和行续符(反斜杠)进行换行:

key: "String \
  with long c\
  ontent"

但是需要注意一个问题,如果换行符后面的行以空格开头,那么它需要进行转义(因为在其他地方会被去除):

key: "String\
  \ with lon\
  g content"
如果字符串中包含换行符,需要使用C样式的\n进行书写。
另请参阅此问题

如果在其他位置剥离,你能否更新你的答案并提供它将被剥离的“位置”信息?请同时说明是哪个解析器(哪种语言的)这么做的。我只看到有解析器会在原地剥离多行字符串的前导/尾随空格。 - Anthon

-4

对我来说,以上的解决方案都没用,在Jekyll项目的一个YAML文件中。尝试了很多选项后,我意识到带有 <br> 的HTML注入也可以解决问题,因为最终所有东西都会呈现为HTML:

name: | In a village of La Mancha <br> whose name I don't <br> want to remember.

至少这种方法对我有效。我不知道与此方法相关的问题。


6
你的解决方案涉及到了一个不同的问题:在你的情况下,你希望通过处理YAML使得换行符出现在渲染后的HTML中。HTML和YAML之间没有隐含的关系。即使YAML会传递常规换行符,HTML也会忽略它们。最终,提问者的问题与在YAML本身中使用换行符以防止出现非常长的行有关。它并不关心数据最终如何呈现。为什么要这样说?因为这解释了为什么这里给出的所有其他解决方案在你的情况下都不起作用。 - Thomas Urban

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接