1. 概述

本文将详细介绍在 YAML 中如何优雅地处理多行字符串。

为了能够解析并测试我们的 YAML 文件,会使用 SnakeYAML 库 进行演示。这个库在 Java 生态中非常常见,尤其在配置解析场景下广泛使用。

2. 多行字符串的基本处理方式

在深入之前,先封装一个通用方法,用于从 YAML 文件中读取指定 key 的字符串值:

String parseYamlKey(String fileName, String key) {
    InputStream inputStream = this.getClass()
      .getClassLoader()
      .getResourceAsStream(fileName);
    Map<String, String> parsed = yaml.load(inputStream);
    return parsed.get(key);
}

✅ 该方法简洁实用,适合单元测试或配置加载场景。
⚠️ 注意:实际项目中建议加上空值判断和异常处理,避免踩坑。

接下来,我们将重点介绍 YAML 提供的几种多行字符串写法,并对比它们的行为差异。

3. 字面量风格(Literal Style)—— 使用 |

这是最常用的方式之一,使用竖线符号 | 表示。它的特点是:

  • ✅ 保留所有行内换行符
  • ❌ 默认会将末尾的多个空行压缩为一个换行

示例文件 literal.yaml

key: |
  Line1
  Line2
  Line3

解析结果:

String key = parseYamlKey("literal.yaml", "key");
assertEquals("Line1\nLine2\nLine3", key);

可以看到每行之间的换行都被保留了。

3.1 包含首尾空行的情况

看下面这个更复杂的例子 literal2.yaml

key: |


  Line1

  Line2

  Line3


...

注意开头和结尾都有多个空行。解析后:

String key = parseYamlKey("literal2.yaml", "key");
assertEquals("\n\nLine1\n\nLine2\n\nLine3\n", key);

✅ 结果说明:

  • 开头的两个空行被完整保留
  • 结尾的多个空行被压缩成一个 \n

这就是 YAML 的默认“块裁剪”(block chomping)行为。

3.2 使用 |+ 保留结尾空行(Keep)

如果想保留结尾的所有空行,可以用 |+

literal_keep.yaml 内容:

key: |+
  Line1
  Line2
  Line3


...

解析结果:

String key = parseYamlKey("literal_keep.yaml", "key");
assertEquals("Line1\nLine2\nLine3\n\n", key);

✅ 结尾两个 \n 都保留了,适合需要精确控制格式的场景,比如脚本模板。

3.3 使用 |- 去除结尾空行(Strip)

相反,若想彻底去掉结尾换行,使用 |-

literal_strip.yaml 内容:

key: |-
  Line1
  Line2
  Line3

...

解析结果:

String key = parseYamlKey("literal_strip.yaml", "key");
assertEquals("Line1\nLine2\nLine3", key);

✅ 结尾所有换行都被清除,适合拼接 SQL 或命令行指令时防止多余换行。

总结一下 | 的三种变体:

写法 行为描述
` `
` +`
` -`

4. 折叠风格(Folded Style)—— 使用 >

使用 > 符号时,YAML 会自动将连续的非空行“折叠”成空格连接,适合写自然语言段落。

示例 folded.yaml

key: >
  Line1
  Line2
  Line3

解析结果:

String key = parseYamlKey("folded.yaml", "key");
assertEquals("Line1 Line2 Line3", key);

✅ 换行被替换为空格,适合写说明性文本。

4.1 处理空行分段

如果中间有空行,会被视为段落分隔:

folded2.yaml

key: >
  Line1
  Line2


  Line3


...

解析结果:

String key = parseYamlKey("folded2.yaml", "key");
assertEquals("Line1 Line2\n\nLine3\n", key);

✅ 解析逻辑:

  • Line1Line2 被空格连接
  • 空行保留为 \n\n,形成段落分隔
  • 结尾空行仍被压缩为一个 \n

⚠️ 注意:> 也支持 >+>- 来控制首尾空行行为,规则与 | 完全一致。

5. 引号中的多行字符串

除了块样式,也可以用引号直接写多行字符串。

5.1 双引号:支持转义字符

双引号中可以直接使用 \n 表示换行:

key: "Line1\nLine2\nLine3"

解析结果:

String key = parseYamlKey("plain_double_quotes.yaml", "key");
assertEquals("Line1\nLine2\nLine3", key);

✅ 简单粗暴,适合短文本或动态生成的配置。

5.2 单引号:转义字符无效

单引号中 \n 不会被解析为换行,而是原样保留:

key: 'Line1\nLine2

  Line3'

注意中间有一个空行,这才是真正的换行来源。

解析结果:

String key = parseYamlKey("plain_single_quotes.yaml", "key");
assertEquals("Line1\\nLine2\nLine3", key);

\n 被当作普通字符,输出为 \\n
✅ 真正的换行来自实际的空行

⚠️ 踩坑提示:新手常误以为单引号里写 \n 就能换行,结果发现没生效,原因就在这里。

6. 总结

YAML 提供了多种方式处理多行字符串,选择哪种取决于你的使用场景:

风格 适用场景
` /
> / >+ / >- 自然语言段落、说明文本
双引号 + \n 简单固定的多行文本
单引号 需要字面量输出 \n 的场景

✅ 推荐实践:

  • 写 Shell 脚本用 |-,避免结尾多余换行
  • 写文档说明用 >,阅读更舒适
  • 动态配置拼接用双引号 + \n,清晰明了

所有示例代码已上传至 GitHub:https://github.com/eugenp/tutorials/tree/master/libraries-data-io


原始标题:Breaking YAML Strings Over Multiple Lines