PaseclCase String to Uppercase separated by underscore

Viewed 1068

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?

6 Answers

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("_"));
}

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

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.

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);

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

str = String.join("_",str.split("(?=\\p{Upper})")).toUpperCase();

You can use Guava's CaseFormat.

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

Demo!

Related