Regex for converting CamelCase to camel_case in java
JavaRegexStringJava Problem Overview
I understand why the desired output is not given for converting using regex a string like FooBar
to Foo_Bar
which instead gives Foo_Bar_
. I could have done something with String.substring substring(0, string.length() - 2)
or just replaced the last character, but I think there is a better solution to such a scenario.
Here is the code:
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
*/
Question: Looking for a neater way to get the desired output?
Java Solutions
Solution 1 - Java
See this question and CaseFormat
from guava
in your case, something like:
CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "SomeInput");
Solution 2 - Java
bind the lower case and upper case as two group,it will be ok
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());
}
}
Solution 3 - Java
You can use below code snippet:
String replaceAll = key.replaceAll("(.)(\\p{Upper})", "$1_$2").toLowerCase();
Solution 4 - Java
I can't provide RegEx, it would be insanely complex anyway.
Try this function with automatic recognition of acronyms.
Unfortunately Guava lib doesn't auto detect upper case acronyms, so "bigCAT" would be converted to "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();
}
Solution 5 - Java
Why not simply match prior character as a not start of line $
?
String text = "CamelCaseToSomethingElse";
System.out.println(text.replaceAll("([^_A-Z])([A-Z])", "$1_$2"));
Note that this version is safe to be performed on something that is already camel cased.
Solution 6 - Java
Add a zero-width lookahead assertion.
http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
Read the documentation for (?=X)
etc.
Personally, I would actually split the string, then recombine it. This may even be faster when done right, and it makes the code much easier to understand than regular expression magic. Don't get me wrong: I love regular expressions. But this isn't really a neat regular expression, nor is this transformation a classic regexp task. After all it seems you also want to do lowercase?
An ugly but quick hack would be to replace (.)([A-Z]+)
with $1_$2
and then lowercase the whole string afterwards (unless you can do perl-style extrended regexps, where you can lowercase the replacement directly!). Still I consider splitting at lower-to-upper transition, then transforming, then joining as the proper and most readable way of doing this.
Solution 7 - Java
Not sure it's possible to have something really solide with pure regex. Especially to support acronyms.
I have made a small function, inspired by @radzimir answer, that supports acronyms and no alphabetic character:
From 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();
}
Solution 8 - Java
public class ReplaceFromCameltoSnake {
public static void main(String args[]){
String s1=" totalAmountWithoutDiscount";
String replaceString=s1.replaceAll("([A-Z]+)","\\_$1").toLowerCase();
System.out.println(replaceString);
}
}
Solution 9 - Java
([A-Z][a-z\d]+)(?=([A-Z][a-z\d]+))
Should search for a capital letter followed by lowercase letters. The positive lookahead will look for another word starting with a capital letter followed by lowercase letters but will NOT include it in the match.
Look here: http://regexr.com?30ooo
Solution 10 - Java
I am writing this answer if somebody doesn't want to use Guava as below for any reason.
CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "SomeInput");
In our case we had problem with storage. There is another special case with Guava: if we have "Ph_D" as input, then we are going to get "ph__d" with two underscores.
The code below worked as long as I tested it.
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;
}
}
Solution 11 - Java
I've had to implement this to convert some keys in camel case format to lower case with underscores. The regular expression I came up with is:
(?<!^|_|[A-Z])([A-Z])
In english it stands for capital letter which is not preceded by the start of the string, an underscore or another capital letter.
In the samples below, the character in bold are the ones that should produce a match using the aforementioned regular expression:
- CamelCaseToSomethingElse
- camelCaseToSomethingElse
- camel_case_to_something_else
- Camel_Case_To_Something_Else
- CAMEL_CASE_TO_SOMETHING_ELSE
Notice the expression does not affect string that are already in lower case + underscore format.
The replacement pattern would be:
_l$1
Which means lower case of first capturing group, first capturing group being the capital letter. You could lower case the whole string afterwards as well to normalize the last two samples from the list above.
Solution 12 - Java
Here my solution with 3 regular expression:
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
The result:
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
Solution 13 - Java
You can easily convert String to camel case using Stream API from Java 8 and method StringUtils.capitalize(..) from commons-lang
public String toCamelCase(String str) {
return Arrays.stream(str.split("_"))
.map(StringUtils::capitalize)
.collect(Collectors.joining());
}