1. 概述
在处理字符串集合时,使用特定分隔符将这些字符串连接起来是一项常见的任务。幸运的是,我们有许多解决方案可供选择,包括使用String.join()
方法和Collectors.joining()
方法。
在这篇快速教程中,我们将探索一个有趣的字符串连接问题:以更自然语言的方式连接字符串。
2. 问题介绍
让我们通过一个例子来理解这个问题。假设我们有一个字符串列表{“A”, “B”, “C”, “D”}
。如果我们想用逗号作为分隔符,结果将是“A, B, C, D”
。到目前为止,一切正常。
然而,如果我们要得到遵循英语语法的连接结果,期望的结果应该是“A, B, C and D”
或“A, B, C, and D”
。稍后我们会解释为什么会有两种形式。但至少我们知道,这并不是直接通过String.join()
或Collectors.joining()
方法调用能得到的结果。
在上述示例中,“C”
和“and”
之间的逗号被称为牛津逗号或哈佛逗号。关于哪种风格更为精确,存在一些讨论。但这不是我们的重点。我们的目标是创建一个方法来支持这两种情况。
因此,给定一个包含超过两个字符串元素的列表,例如{“A”, “B”, “C”, …, “X”, “Y”}
,根据需求,我们可能得到两种结果:
- 使用牛津逗号 -
“A, B, C, …, X and Y”
- 不使用牛津逗号 -
“A, B, C, …, X, and Y”
此外,我们只讨论了至少包含三个元素的列表。如果列表包含少于三个元素,结果可能会有所不同:
- 对于空列表,返回空字符串,所以
{ }
变为“”
- 对于只有一个元素的列表,返回该元素。例如,
{“A”}
变为“A”
- 当处理包含两个字符串元素的列表时,不使用逗号将它们组合在一起。例如,
{“A”, “B”}
变成“A and B”
接下来,我们将创建一个方法,以自然语言的方式连接字符串列表。为了简化,我们假设输入列表不为null,并且不包含null或空字符串元素。实际上,如果列表包含空或null字符串,我们可以在实际操作前先进行过滤。
3. 创建joinItemsAsNaturalLanguage()
方法
首先,让我们看看方法实现,然后理解它是如何工作的:
String joinItemsAsNaturalLanguage(List<String> list, boolean oxfordComma) {
if (list.size() < 3) {
return String.join(" and ", list);
}
// list has at least three elements
int lastIdx = list.size() - 1;
StringBuilder sb = new StringBuilder();
return sb.append(String.join(", ", list.subList(0, lastIdx)))
.append(oxfordComma ? ", and " : " and ")
.append(list.get(lastIdx))
.toString();
}
现在,让我们快速浏览代码。首先,我们处理列表包含不到三个元素的情况,使用String.join(“ and “, list)
。
然后,如果列表包含三个或更多的字符串,我们使用“, “
作为分隔符连接输入子列表(排除最后一个字符串)中的元素。最后,我们将连接后的结果与最后一个元素加上“and”。当然,也要考虑牛津逗号选项。
值得注意的是,我们不应该先用逗号将所有元素连接起来,然后再替换最后一个逗号为“and”
。这是因为最后一个元素也可能包含逗号。
让我们不使用牛津逗号测试我们的解决方案:
assertEquals("", joinItemsAsNaturalLanguage(emptyList(), false));
assertEquals("A", joinItemsAsNaturalLanguage(List.of("A"), false));
assertEquals("A and B", joinItemsAsNaturalLanguage(List.of("A", "B"), false));
assertEquals("A, B, C, D and I have a comma (,)", joinItemsAsNaturalLanguage(List.of("A", "B", "C", "D", "I have a comma (,)"), false));
最后,使用牛津逗号测试:
assertEquals("", joinItemsAsNaturalLanguage(emptyList(), true));
assertEquals("A", joinItemsAsNaturalLanguage(List.of("A"), true));
assertEquals("A and B", joinItemsAsNaturalLanguage(List.of("A", "B"), true));
assertEquals("A, B, C, D, and I have a comma (,)", joinItemsAsNaturalLanguage(List.of("A", "B", "C", "D", "I have a comma (,)"), true));
4. 总结
在这篇文章中,我们讨论了如何以自然语言的方式连接字符串列表的问题。我们也学习了如何创建一个解决此问题的方法。如往常一样,每个示例的完整源代码可在GitHub上找到。