Regex for split only if all string are quoted

Viewed 113

Is there a way to return the delimiters for a split only if all strings are quoted using regex?

Considering that the string should be splitted by "-".

Using ((?<=")-(?=")) it matches the 2 - and that's ok with the following sample: "abc"-"123"-"zxc".

But the regex matches 2 - in the following samples when should not detect any -:

abc"-"123"-"zxc"

"abc"-"123"-"zxc

Using -(?=([^"]*"[^"]*")*[^"]*$) it matches the 2 - and that's ok with the following samples: "abc"-"123"-"zxc".

It does not match any - on the following samples and that's ok too:

"abc"-"123"-"zxc

"abc"-"123"-zxc"

But the regex matches 2 - in the following samples when should not detect any -:

abc"-"123"-"zxc"

abc-"123"-"zxc"

"abc"-"123"-zxc

I was thinking to apply 2 regex, if the string matches with ^"[\da-z\-"]*"$ I would apply the split with ((?<=")-(?=")) but I feel that there is a way that I haven't tried yet.

2 Answers

If you want to return values around the delimiters, you might use a capture group in combination with using the \G anchor.

\G("[^"]*")(?=(?:-"[^"]*")*$)(?:-|$)

Explanation

  • \G Assert the position at the end of the previous match or at the start of the string
  • ("[^"]*") Match from a double quote till a double quote
  • (?=(?:-"[^"]*")*$) Assert optional part of -".." at the right until the end of the string
  • (?:-|$) Match either -, or end of string

See a Regex demo or a Java demo

In Java with doubled backslashes:

String regex = "\\G(\"[^\"]*\")(?=(?:-\"[^\"]*\")*$)(?:-|$)";

For example

String strings[] = {
    "\"abc\"-\"123\"-\"zxc1\"",
    "\"abc\"-\"123\"-\"zxc2",
    "\"abc\"-\"123\"-zxc3\"",
    "abc\"-\"123\"-\"zxc4\"",
    "\"abc\"-\"123\"-\"zxc5",
    "abc\"-\"123\"-\"zxc6\"",
    "abc-\"123\"-\"zxc7\"",
    "\"abc\"-\"123\"-zxc8"
};
String regex = "\\G(\"[^\"]*\")(?=(?:-\"[^\"]*\")*$)(?:-|$)";
Pattern pattern = Pattern.compile(regex);
for (String s : strings) {
    Matcher matcher = pattern.matcher(s);

    while (matcher.find()) {
        for (int i = 1; i <= matcher.groupCount(); i++) {
            System.out.println(matcher.group(i));
        }
    }
}

Output

"abc"
"123"
"zxc1"

I would just use String#matches with the following pattern:

"[^"]+"(?:-"[^"]+")*

Script:

String input = "\"abc\"-\"123\"-\"zxc\"";
if (input.matches("\"[^\"]+\"(?:-\"[^\"]+\")*")) {
    System.out.println("MATCH");  // prints MATCH
}

String input = "abc\"-\"123\"-\"zxc\"";  // missing leading quote
if (input.matches("\"[^\"]+\"(?:-\"[^\"]+\")*")) {
    System.out.println("MATCH");  // does not print
}
Related