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);
✅ 解析逻辑:
Line1
和Line2
被空格连接- 空行保留为
\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