1. 概述
驼峰命名法(camel case)和下划线命名法(snake case)是编程中两种常见的命名规范。驼峰命名法通过大写字母标记单词边界(如 camelCaseExample
),而下划线命名法则使用下划线分隔单词(如 snake_case_example
)。
本教程将探讨在Java中实现这种转换的几种方法。
2. 转换原理分析
将驼峰命名转换为下划线命名需要完成三个核心步骤:
- ✅ 识别单词边界(即大写字母位置)
- ✅ 在边界处插入下划线(
_
) - ✅ 将所有字母转为小写
例如:
- 输入:
"convertCamelCase"
- 输出:
"convert_camel_case"
理解这个转换逻辑后,我们来看看具体实现方案。
3. 手动实现方案
最直接的方式是遍历字符串字符,遇到大写字母时插入下划线:
public static String convertCamelCaseToSnake(String input) {
StringBuilder result = new StringBuilder();
for (char c : input.toCharArray()) {
if (Character.isUpperCase(c)) {
result.append("_").append(Character.toLowerCase(c));
} else {
result.append(c);
}
}
return result.toString();
}
代码逻辑解析:
- 遍历字符串中的每个字符
- 遇到大写字母时:
- 先添加下划线
- 再将该字母转为小写
- 其他字符直接追加
测试用例验证:
@Test
public void whenConvertNormalCamelCase_thenGetCorrectSnakeCase() {
String input = "convertCamelCase";
String expected = "convert_camel_case";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnake(input));
}
@Test
public void whenConvertNotNormalCamelCase_thenGetCorrectSnakeCase() {
String input = "convertCCamelCase";
String expected = "convert_c_camel_case";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnake(input));
}
@Test
public void whenConvertAlreadySnakeCase_thenGetUnchangedSnakeCase() {
String input = "snake_case";
String expected = "snake_case";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnake(input));
}
@Test
public void whenConvertAllLowerCaseString_thenGetUnchangedString() {
String input = "snakecase";
String expected = "snakecase";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnake(input));
}
@Test
public void whenConvertOtherEdgeCases_thenGetCorrectSnakeCases() {
// 空字符串测试
Assertions.assertEquals("", CamelToSnakeCaseConverter.convertCamelCaseToSnake(""));
// 特殊字符测试
String input = "sn@keCase#";
String expected = "sn@ke_case#";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnake(input));
}
4. 正则表达式方案
利用正则表达式可以更简洁地实现转换:
public static String convertCamelCaseToSnakeRegex(String input) {
return input
.replaceAll("([A-Z])(?=[A-Z])", "$1_")
.replaceAll("([a-z])([A-Z])", "$1_$2")
.toLowerCase();
}
正则表达式解析:
replaceAll("([A-Z])(?=[A-Z])", "$1_")
- 匹配连续大写字母中的边界(如
CC
→C_C
) - 使用正向预查
(?=[A-Z])
确保后面还有大写字母
- 匹配连续大写字母中的边界(如
replaceAll("([a-z])([A-Z])", "$1_$2")
- 匹配小写字母后跟大写字母的情况(如
aA
→a_A
)
- 匹配小写字母后跟大写字母的情况(如
最后统一转为小写
同样通过测试用例验证:
@Test
public void whenConvertNormalCamelCase_thenGetCorrectSnakeCase() {
String input = "convertCamelCase";
String expected = "convert_camel_case";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnakeRegex(input));
}
@Test
public void whenConvertNotNormalCamelCase_thenGetCorrectSnakeCase() {
String input = "convertCCamelCase";
String expected = "convert_c_camel_case";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnakeRegex(input));
}
@Test
public void whenConvertAlreadySnakeCase_thenGetUnchangedSnakeCase() {
String input = "snake_case";
String expected = "snake_case";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnakeRegex(input));
}
@Test
public void whenConvertAllLowerCaseString_thenGetUnchangedString() {
String input = "snakecase";
String expected = "snakecase";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnakeRegex(input));
}
@Test
public void whenConvertOtherEdgeCases_thenGetCorrectSnakeCases() {
// 空字符串测试
Assertions.assertEquals("", CamelToSnakeCaseConverter.convertCamelCaseToSnakeRegex(""));
// 特殊字符测试
String input = "sn@keCase#";
String expected = "sn@ke_case#";
Assertions.assertEquals(expected, CamelToSnakeCaseConverter.convertCamelCaseToSnakeRegex(input));
}
5. 边界情况处理
实际开发中需要特别注意这些边界情况:
场景 | 预期行为 | 处理要点 |
---|---|---|
✅ 空字符串 | 返回空字符串 | 直接返回 |
✅ 全小写字符串 | 保持不变 | 无需处理 |
✅ 已是下划线命名 | 保持不变 | 避免重复转换 |
⚠️ 特殊字符 | 保留原样 | 不影响字母转换 |
踩坑提示:连续大写字母(如
XMLHttpRequest
)需要特殊处理,否则会变成x_m_l_http_request
而非期望的xml_http_request
。本方案已通过正则表达式优化解决此问题。
6. 总结
我们探讨了两种Java中驼峰命名转下划线命名的实现方案:
手动遍历方案
- 优点:逻辑直观,易于调试
- 缺点:代码量稍多
正则表达式方案
- 优点:简洁高效,一行搞定
- 缺点:需要理解正则表达式
根据实际场景选择即可——简单场景用正则更优雅,复杂逻辑需要调试时手动方案更可控。两种方案均已通过完整测试用例验证,可直接用于生产环境。