用于在 java 中将 CamelCase 转换为 camel_case 的正则表达式
Posted
技术标签:
【中文标题】用于在 java 中将 CamelCase 转换为 camel_case 的正则表达式【英文标题】:Regex for converting CamelCase to camel_case in java 【发布时间】:2012-05-05 19:44:05 【问题描述】:我理解为什么使用正则表达式将FooBar
之类的字符串转换为Foo_Bar
时没有给出所需的输出,而是给出了Foo_Bar_
。我可以用 String.substring substring(0, string.length() - 2)
做点什么,或者只是替换最后一个字符,但我认为对于这种情况有更好的解决方案。
代码如下:
String regex = "([A-Z][a-z]+)";
String replacement = "$1_";
"CamelCaseToSomethingElse".replaceAll(regex, replacement);
/*
outputs: Camel_Case_To_Something_Else_
desired output: Camel_Case_To_Something_Else
*/
问题:正在寻找一种更简洁的方法来获得所需的输出?
【问题讨论】:
这个问题类似于***.com/questions/4886091/… 【参考方案1】:您可以使用来自 Java 8 的 Stream API 和来自 commons-lang 的方法 StringUtils.capitalize(..) 轻松地将字符串转换为驼峰式大小写
public String toCamelCase(String str)
return Arrays.stream(str.split("_"))
.map(StringUtils::capitalize)
.collect(Collectors.joining());
【讨论】:
【参考方案2】:这是我的 3 个正则表达式的解决方案:
str.replaceAll("([^A-Z])([A-Z0-9])", "$1_$2") // standard replace
.replaceAll("([A-Z]+)([A-Z0-9][^A-Z]+)", "$1_$2") // last letter after full uppercase.
.replaceAll("([0-9]+)([a-zA-Z]+)", "$1_$2").toLowerCase(); // letters after numbers
结果:
thisIsATest: this_is_a_test
EndWithNumber3: end_with_number_3
3ThisStartWithNumber: 3_this_start_with_number
Number3InMiddle: number_3_in_middle
Number3inMiddleAgain: number_3_in_middle_again
MyUUIDNot: my_uuid_not
HOLAMundo: hola_mundo
holaMUNDO: hola_mundo
with_underscore: with_underscore
withAUniqueLetter: with_a_unique_letter
【讨论】:
【参考方案3】:如果有人出于任何原因不想使用 Guava,我正在写这个答案。
CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "SomeInput");
在我们的案例中,我们遇到了存储问题。 Guava 还有一个特殊情况:如果我们将“Ph_D”作为输入,那么我们将得到带有两个下划线的“ph__d”。
只要我测试过,下面的代码就可以工作。
public static String camelCaseToLowerCaseWithUnderscore(String string)
if (string.matches(".*[a-z].*"))
final Matcher matcher = Pattern.compile("(_?[A-Z][a-z]?)").matcher(string);
StringBuffer stringBuffer = new StringBuffer();
matcher.find(); // This is just to escape the first group (beginning of string)
while (matcher.find())
final String group = matcher.group();
if (!group.startsWith("_"))
matcher.appendReplacement(stringBuffer, "_" + group);
matcher.appendTail(stringBuffer);
return stringBuffer.toString().toLowerCase();
else
return string;
【讨论】:
【参考方案4】:不确定是否有可能使用纯正则表达式实现真正可靠的东西。尤其是支持首字母缩略词。
我做了一个小函数,受@radzimir 答案的启发,支持首字母缩略词,没有字母字符:
来自https://gist.github.com/ebuildy/cf46a09b1ac43eea17c7621b7617ebcd:
private static String snakeCaseFormat(String name)
final StringBuilder result = new StringBuilder();
boolean lastUppercase = false;
for (int i = 0; i < name.length(); i++)
char ch = name.charAt(i);
char lastEntry = i == 0 ? 'X' : result.charAt(result.length() - 1);
if (ch == ' ' || ch == '_' || ch == '-' || ch == '.')
lastUppercase = false;
if (lastEntry == '_')
continue;
else
ch = '_';
else if (Character.isUpperCase(ch))
ch = Character.toLowerCase(ch);
// is start?
if (i > 0)
if (lastUppercase)
// test if end of acronym
if (i + 1 < name.length())
char next = name.charAt(i + 1);
if (!Character.isUpperCase(next) && Character.isAlphabetic(next))
// end of acronym
if (lastEntry != '_')
result.append('_');
else
// last was lowercase, insert _
if (lastEntry != '_')
result.append('_');
lastUppercase = true;
else
lastUppercase = false;
result.append(ch);
return result.toString();
【讨论】:
这是一个高质量的答案,它可以处理大多数边缘情况。【参考方案5】:看到这个question和CaseFormat
from guava
在你的情况下,类似于:
CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "SomeInput");
【讨论】:
@eliocs 这个问题没有被标记为 android 和“更整洁的方式”。无论如何感谢您的反对 ;) CaseFormat 链接已离线。替换为here Guava 函数中有一个特殊情况,可能不是每个用户都想要的。如果我们有“Ph_D”,那么您将得到带有两个下划线的“ph__d”。我在这里写信给人们注意【参考方案6】:我必须实现它以将驼峰格式的一些键转换为带下划线的小写。我想出的正则表达式是:
(?<!^|_|[A-Z])([A-Z])
在英文中它代表前面没有字符串开头、下划线或其他大写字母的大写字母。
在下面的示例中,粗体字符是应该使用上述正则表达式产生匹配的字符:
骆驼CaseToSsomethingElse 骆驼CaseToSsomethingElse camel_case_to_something_else Camel_Case_To_Something_Else CAMEL_CASE_TO_SOMETHING_ELSE注意表达式不会影响已经是小写+下划线格式的字符串。
替换模式是:
_l$1
这意味着第一个捕获组的小写,第一个捕获组是大写字母。之后您也可以将整个字符串小写,以规范上面列表中的最后两个样本。
【讨论】:
【参考方案7】:我无法提供正则表达式,反正它会非常复杂。
试试这个自动识别首字母缩写词的功能。
很遗憾,Guava lib 不会自动检测大写首字母缩写词,因此“bigCAT”将被转换为“BIG_C_A_T”
/**
* Convert to UPPER_UNDERSCORE format detecting upper case acronyms
*/
private String upperUnderscoreWithAcronyms(String name)
StringBuffer result = new StringBuffer();
boolean begin = true;
boolean lastUppercase = false;
for( int i=0; i < name.length(); i++ )
char ch = name.charAt(i);
if( Character.isUpperCase(ch) )
// is start?
if( begin )
result.append(ch);
else
if( lastUppercase )
// test if end of acronym
if( i+1<name.length() )
char next = name.charAt(i+1);
if( Character.isUpperCase(next) )
// acronym continues
result.append(ch);
else
// end of acronym
result.append('_').append(ch);
else
// acronym continues
result.append(ch);
else
// last was lowercase, insert _
result.append('_').append(ch);
lastUppercase=true;
else
result.append(Character.toUpperCase(ch));
lastUppercase=false;
begin=false;
return result.toString();
【讨论】:
【参考方案8】:public class ReplaceFromCameltoSnake
public static void main(String args[])
String s1=" totalAmountWithoutDiscount";
String replaceString=s1.replaceAll("([A-Z]+)","\\_$1").toLowerCase();
System.out.println(replaceString);
【讨论】:
$1-用来组团【参考方案9】:将小写和大写分成两组,就可以了
public class Main
public static void main(String args[])
String regex = "([a-z])([A-Z]+)";
String replacement = "$1_$2";
System.out.println("CamelCaseToSomethingElse"
.replaceAll(regex, replacement)
.toLowerCase());
【讨论】:
注意:如果输入字符串中允许单字母单词,例如“thisIsATest”,上面的代码将打印“this_is_atest”。番石榴,在接受的答案中,结果是“this_is_a_test”。 这不适用于以大写字母开头的名称,例如:IBMIsMyCompany
。【参考方案10】:
你可以使用下面的代码sn-p:
String replaceAll = key.replaceAll("(.)(\\pUpper)", "$1_$2").toLowerCase();
【讨论】:
如果我的字符串包含一个数字怎么办 - mode3 以 mode3 结尾,而我想要 mode_3。 它不会像MyUUID
这样将骆驼大小写正确地转换为下划线,我得到了 my_uu_id
。
@Mike/@User3301 试试这个String replaceAll = key.replaceAll("(.)(\\pUpper+|\\d+)", "$1_$2").toLowerCase();
【参考方案11】:
为什么不简单地将前面的字符匹配为非行首$
?
String text = "CamelCaseToSomethingElse";
System.out.println(text.replaceAll("([^_A-Z])([A-Z])", "$1_$2"));
请注意,此版本可以安全地用于已装骆驼皮的东西。
【讨论】:
您是否尝试使用^
和$
作为锚点?因为当您将它们放入字符类时,它们的含义会发生变化。 [^$_A-Z]
匹配任何不是$
、_
或大写字母的字符,我认为这不是您的意思。
不打算作为锚点,我试图不匹配大写字符,$
被错误地添加,因为它是我在类名上使用的一种技术。【参考方案12】:
添加一个零宽度的前瞻断言。
http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
阅读(?=X)
等的文档。
就个人而言,我实际上会拆分字符串,然后重新组合它。如果做得好,这甚至可能更快,并且它使代码比正则表达式更容易理解。不要误会我的意思:我喜欢正则表达式。但这并不是一个真正简洁的正则表达式,这个transformation 也不是一个经典的正则表达式任务。毕竟你似乎也想做小写?
一个丑陋但快速的技巧是将(.)([A-Z]+)
替换为$1_$2
,然后将整个字符串小写(除非您可以执行perl风格的扩展正则表达式,您可以直接将替换小写!)。我仍然认为在从低到高的过渡中拆分,然后转换,然后加入是这样做的正确和最易读的方式。
【讨论】:
是的,最终我也希望它是小写的。 所以我会把它分成匹配[A-Z][a-z]*
的块,小写第一个字母,然后重新加入它们。或者我刚刚添加到主要回复中的替换+小写技巧。【参考方案13】:
([A-Z][a-z\d]+)(?=([A-Z][a-z\d]+))
应搜索大写字母后跟小写字母。正向前瞻将寻找另一个以大写字母开头后跟小写字母的单词,但不会将其包含在匹配项中。
看这里:http://regexr.com?30ooo
【讨论】:
以上是关于用于在 java 中将 CamelCase 转换为 camel_case 的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章
正则表达式在 Redshift 中将 CamelCase 转换为蛇形案例
如何在 R 中将 not.camel.case 转换为 CamelCase
在Ruby中将嵌套哈希键从CamelCase转换为snake_case