2

What's the best way to convert a "PascelCase" string to all upper case separated by underscore like "Pascel_CASE". I wrote this code which works:

  private static String pascelCaseToUpperCaseSeparatedByUnderscore(String s) {
        
        String[] values = s.split("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])");
        
        for (int i = 0, len = values.length; i < len; i++) {
            values[i] = values[i].toUpperCase();
        }
        return String.join("_", values);
    }

However, is there better way say, using a library, to do this?

Arefe
  • 11,321
  • 18
  • 114
  • 168
  • 5
    Does this answer your question? [Regex for converting CamelCase to camel\_case in java](https://stackoverflow.com/questions/10310321/regex-for-converting-camelcase-to-camel-case-in-java) – jnorman Jul 18 '20 at 21:16
  • 1
    @jnorman this kind of answer my question. Thank you. – Arefe Jul 19 '20 at 02:25
  • 1
    The accepted answer in that question, https://stackoverflow.com/a/10310393/13909378, is the exact accepted answer in this question. – jnorman Jul 19 '20 at 03:17
  • 1
    @jnorman many people already write the answer here too, so lets keep it as well. – Arefe Jul 19 '20 at 03:45

6 Answers6

9

Your regex looks complicated at first glance, which might discourage other people who read your code and are not familiar with regex. You can replace it with this more compact and readable one:

"(?=\\p{Upper})"

and in connection with streams this one-liner reads almost like plain text

private static String camelCaseToUpperCaseSeparatedByUnderscore(String s) {
    return Pattern.compile("(?=\\p{Upper})")
                  .splitAsStream(s)
                  .map(String::toUpperCase)
                  .collect(Collectors.joining("_"));
}
Eritrean
  • 15,851
  • 3
  • 22
  • 28
  • 2
    Nice solution +1. You might want to explain how you're splitting on a position rather than a specific string or character (due to the zero width behavior of lookaheads). – WJS Jul 18 '20 at 23:47
  • @Eritrean I am not very good with the regex and still trying to simplify my code. – Arefe Jul 19 '20 at 02:28
5

If you can use Guava you can do:

String camelCase = "CamelCase";

String underscore = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, camelCase);

System.out.println(underscore);

If you just want to use regex you can do:

String underscore = String.join("_", Arrays.asList(camelCase.split("(?=[A-Z])")).stream()
    .map(String::toUpperCase).collect(Collectors.toList()));

You can also use Arrays.stream() instead:

String underscore = Arrays.stream(camelCase.split("(?=[A-Z])")).map(String::toUpperCase)
            .collect(Collectors.joining("_"));

Output

CAMEL_CASE
Oboe
  • 2,643
  • 2
  • 9
  • 17
3

Using regex for this task seems like overkill

private static String camelCaseToUpperCaseSeparatedByUnderscore(String s) {
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < s.length(); i++) {
        sb.append(Character.toUpperCase(s.charAt(i)));
        if(i < s.length() - 1 && Character.isLowerCase(s.charAt(i)) && Character.isUpperCase(s.charAt(i + 1)))
            sb.append('_');
    }
    return sb.toString();
}

Just iterate over the string, add the current character converted to uppercase and whenever you have a switch from lowercase to uppercase, add an underscore.

Tmrd993
  • 51
  • 2
3

You can use java 8 streams and collectors.

    StringBuilder result =
        "CamelCase".chars().collect(
                StringBuilder::new,
                //if ch is not the first letter and is uppercase, prepend underscore, then add uppercased ch
                (sb, ch) -> sb.append(sb.length()>0 && Character.isUpperCase(ch) ? "_" : "").append(Character.toUpperCase((char)ch)),
                //combine results
                (sb1, sb2) -> sb1.append(sb2)
        );
    System.out.println(result);
yavuzkavus
  • 1,268
  • 11
  • 17
3

And making use of @Eritrean's regex you can also do it like this.

str = String.join("_",str.split("(?=\\p{Upper})")).toUpperCase();
WJS
  • 36,363
  • 4
  • 24
  • 39
1

You can use Guava's CaseFormat.

private static String camelCaseToUpperCaseSeparatedByUnderscore(String s) {
    return CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, s);
}

Demo!

Unmitigated
  • 76,500
  • 11
  • 62
  • 80