Java: Searching an elegant way to split String

Viewed 621

I know there are a lot questions and answers to regex related topics and I already read a lot of them and tried several ways myself but they all do not seem to be easy to understand. So I wanted to ask if someone can help me to do it better?

My Problem

I get a String which looks like this (it's a german formatted string):

"[Header: 150,00;20.02.2019;Bemerkung\]\;;\;Andere Bemerkung;]"

As you can see the different columns are separated by semicolon ; but unfortunately semicolon characters are also allowed to occur in the comment fields (for example \;Andere Bemerkung) and thus are escaped (with \ by the source system from which I get the string delivered.

My task now is to validate that the number of columns in this string is correct, but not changing the string itself. In this case the number of columns should be 5

My current solution

As I'm not good with regex and time is short to become now an expert for solving this problem, I use different Java API's to split the String:

"[Header: 150,00;20.02.2019;Bemerkung\\]\\;;\\;Andere Bemerkung;]".replace("\\;", " ").split(";")

I use the replace API because it doesn't take a regex expression but just a String as argument and so I am able to replace the \; with whitespace and then successfully split the String into the columns and I am able to validate the result. Because Strings are immutable it works fine, but the solution looks like there are for sure better ways to do so in Java.

I also searched in the apache-commons-lang and apache-commons-text API and also in the provided spring-boot APIs, but was not able to find any better solution.

What I also tried is a regex with a blacklist of expressions because in my case this blacklist would be very short, but unfortunately I think I was not even close to a solution.

Do you have any better solution?

1 Answers

First of all, if you do not escape backslashes, or there cannot be any literal backslashes in the string you may split with a ; that is not preceded with \:

s.split("(?<!\\\\);")

If there can be any escaped entities, use

(?:[^;\\]|\\.)++

regex to match the required fields. See this regex demo. (?:[^;\\]|\\.)++ will match 1 or more repetitions of any char but ; and \ or a \ followed with any char. Compile the pattern with Pattern.DOTALL flag if there can be line breaks in the content to split.

Java demo:

String s = "[Header: 150,00;20.02.2019;Bemerkung\\]\\;;\\;Andere Bemerkung;]";
List<String> result = new ArrayList<>();
Pattern pattern = Pattern.compile("(?:[^;\\\\]|\\\\.)++");
Matcher matcher = pattern.matcher(s);
while (matcher.find()){
    result.add(matcher.group(0)); 
} 
System.out.println(result);
// => [[Header: 150,00, 20.02.2019, Bemerkung\]\;, \;Andere Bemerkung, ]]
Related