4

I'm trying to write regex that will split a Java string like this:

300x250,468x60,300x400v(480x320,768x1024,100x100),400x300v,640x480v(200x200,728x90)

in to something like this:

300x250 
468x60
300x400v(480x320,768x1024,100x100)
400x300v
640x480v(200x200,728x90)

I've been trying \,(\()? but this ends up selecting the commas in the parentheses as well.

Chenmunka
  • 685
  • 4
  • 21
  • 25
akburg
  • 43
  • 1
  • 3
  • possible duplicate of [Java splitting a string while ignoring any delimiters between brackets](http://stackoverflow.com/questions/9656212/java-splitting-a-string-while-ignoring-any-delimiters-between-brackets) – jlordo Feb 10 '13 at 00:04
  • 4
    @jlordo - The linked question is **not a duplicate**. The user is not attempting to balance brackets - there's only one layer, which is totally possible using regex. – JDB Feb 10 '13 at 02:41
  • @Cyborgx37: If you're sure, please post a regex solution. The answer by Stephen C does not work. – jlordo Feb 10 '13 at 10:51
  • 1
    @jlordo - Pshemo already has. `,(?![^(]*\))` works great on http://myregexp.com. Here's a link to it on: http://regexr.com?33njn – JDB Feb 10 '13 at 14:12
  • @Cyborgx37: Overread the regex part of his answer. And yes, it works just fine. – jlordo Feb 10 '13 at 14:30

2 Answers2

7

If you have to use regex you can split on ,(?![^(]*\\))

If not then one simple iteration over characters can do the trick

String data="300x250,468x60,300x400v(480x320,768x1024,100x100),400x300v,640x480v(200x200,728x90)";

List<String> tokens=new ArrayList<>();
StringBuilder buffer=new StringBuilder();

int parenthesesCounter=0;

for (char c : data.toCharArray()){
    if (c=='(') parenthesesCounter++;
    if (c==')') parenthesesCounter--;
    if (c==',' && parenthesesCounter==0){
        //lets add token inside buffer to our tokens
        tokens.add(buffer.toString());
        //now we need to clear buffer  
        buffer.delete(0, buffer.length());
    }
    else 
        buffer.append(c);
}
//lets not forget about part after last comma
tokens.add(buffer.toString());

String[] splitedArray=tokens.toArray(new String[tokens.size()]);

//lets test what is inside our array
for (String s : splitedArray)
    System.out.println(s);

Output

300x250
468x60
300x400v(480x320,768x1024,100x100)
400x300v
640x480v(200x200,728x90)
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • Your example output is pretty confusing and misleading. :) Also, I don't think you need to escape the opening paren if it's inside a character class. – JDB Feb 10 '13 at 14:13
  • @Cyborgx37 hope it is less confusing now :) – Pshemo Feb 10 '13 at 15:08
1

akburg, resurrecting this question for completion because it had another simple solution that wasn't mentioned. This situation is similar to Match (or replace) a pattern except in situations s1, s2, s3 etc.

Here's our simple regex:

\([^)]*\)|(,)

The left side of the alternation matches complete (parentheses) tags. We will ignore these matches. The right side matches and captures commas to Group 1, and we know they are the right commas because they were not matched by the expression on the left.

This program shows how to use the regex (see the results at the bottom of the online demo):

import java.util.*;
import java.io.*;
import java.util.regex.*;
import java.util.List;

class Program {
public static void main (String[] args) throws java.lang.Exception  {

String subject = "300x250,468x60,300x400v(480x320,768x1024,100x100),400x300v,640x480v(200x200,728x90)";
Pattern regex = Pattern.compile("\\([^)]*\\)|(,)");
Matcher m = regex.matcher(subject);
StringBuffer b= new StringBuffer();
while (m.find()) {
if(m.group(1) != null) m.appendReplacement(b, "SplitHere");
else m.appendReplacement(b, m.group(0));
}
m.appendTail(b);
String replaced = b.toString();
String[] splits = replaced.split("SplitHere");
for (String split : splits) System.out.println(split);
} // end main
} // end Program

Reference

How to match (or replace) a pattern except in situations s1, s2, s3...

Community
  • 1
  • 1
zx81
  • 41,100
  • 9
  • 89
  • 105