-1

Suppose I have string like FOO_BAR or foo_bar or Foo_Bar, I want to convert it to customised snake case like below

 FOO_BAR ->   Foo Bar
`foo_bar` -> `Foo Bar`
`Foo_Bar` -> `Foo Bar`

As you can notice all three inputs provide the same output, capitalise the first character before every underscore and first one, and remove the _ (underscore).

Looked into various libraries like guava and apache but as this is customized version couldn't find any Out of the box solution.

Tried below code but and make it work but its looking bit complex

str.replaceAll("([a-z])([A-Z])", "$1_$2").replaceAll("_", " ")

Output of above code is like FOO BAR basically all characters in uppercase, that i can fix in another iteration but looking for something more efficient and simple.

Amit
  • 30,756
  • 6
  • 57
  • 88

2 Answers2

2

Here's a simple implementation. I would add a few more test cases before I trusted it. It does not handle Unicode characters of more than two bytes.

public class Snakify {
    public static String toSnake(String in) {
        boolean first = true;
        boolean afterUnderscore = false;
        char[] chars = in.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if ((first || afterUnderscore) && Character.isAlphabetic(chars[i])) {
                chars[i] = Character.toUpperCase(chars[i]);
                first = false;
                afterUnderscore = false;
            } else if (chars[i] == '_') {
                chars[i] = ' ';
                afterUnderscore = true;
            } else if (Character.isAlphabetic(chars[i])) {
                chars[i] = Character.toLowerCase(chars[i]);
            }
        }
        return new String(chars);
    }

    public static void main(String[] args) {
        System.out.println(toSnake("FOO_BAR").equals("Foo Bar"));
        System.out.println(toSnake("foo_bar").equals("Foo Bar"));
        System.out.println(toSnake("Foo_Bar").equals("Foo Bar"));
        System.out.println(toSnake("àèì_òù_ÀÈÌ").equals("Àèì Òù Àèì"));
    }
}
tgdavies
  • 10,307
  • 4
  • 35
  • 40
2

Just for a bit of fun, here is a stream-based answer:

var answer = Arrays.stream(s.split("_"))
             .map(i -> i.substring(0, 1).toUpperCase() + i.substring(1).toLowerCase())
             .collect(Collectors.joining(" "));

Matt Clarke
  • 757
  • 4
  • 15
  • do you try that? \`foo_bar\` -> \`Foo Bar\`? or \`foo_bar\` -> Foo Bar? – 时间只会一直走 Sep 08 '22 at 10:02
  • 2
    @Amit-ESenthusiast If we are talking about efficiency, the [answer by tgdavies](https://stackoverflow.com/a/73646630/17795888) should be the best, single iteration, no intermediate strings, etc. About readability and simplicity though, stream beats the rest, true. – Chaosfire Sep 08 '22 at 10:09
  • @Chaosfire agree, upvoting his answer as well but I need both hence selected the stream answer and upvoting others – Amit Sep 08 '22 at 10:24