tags:

views:

126

answers:

4

I have this input string(oid) : 1.2.3.4.5.66.77.88.99.10.52

I want group each number into 3 to like this

Group 1 : 1.2.3

Group 2 : 4.5.66

Group 3 : 77.88.99

Group 4 : 10.52

It should be very dynamic depending on the input. If it has 30 numbers meaning it will return 10 groups.

I have tested using this regex : (\d+.\d+.\d+)

But the result is this

Match 1: 1.2.3

Subgroups:

1: 1.2.3

Match 2: 4.5.66

Subgroups:

1: 4.5.66

Match 3: 77.88.99

Subgroups:

1: 77.88.99

Where as still missed one more matches.

Can anyone help me to provide the Regex. Thank you

+1  A: 

If you want to match up to three digits, you should try:

((?:\d+\.?){1,3})

The {1,3} part matches 1-3 of the preceding item (which is one or more digits followed by a literal .. Note that the dot is escaped so that it doesn't match any character.

Edit

Further explanation: The (?: ) part is a grouping that cannot be used for backreferences (tends to be faster), see section 4.3 here for more information. You could, of course, also just use ((\d+\.?){1,3}) if you prefer. For more information on {1,3}, see here under "Limiting Repetition".

Edit (2)

Fixed error pointed out by dtmunir. An alternative way that is a bit more explicit (and doesn't catch the extra "." at the end of the early groups) is:

((?:\d+\.){0,2}\d+)
Al
A: 

Al that will not capture the 52. But this one in fact will:

((?:\d+\.?){1,3})

The only change is adding the question mark after the . This allows it to accept the last number without having a period after it

Explanation (EDIT):

The \d+ as you can imagine captures consecutive digits.

The \. captures a period

The \.? captures a period, but allows the inner group to not require a period at the end

The (?:\d+\.?) defines "one group" which in your case you want to be 3 numbers.

The {1,3} sets the limits. It requires a minimum of 1 inner group and at most 3 inner groups. These groups may or may not end with a period.

dtmunir
but doesn't this captures the hole input as one group
stefita
no stefita. The {1,3} input limits it to 3 numbers per group maximum
dtmunir
Good point, thank you, I've edited my answer accordingly and added a more explicit way of matching it. However note that your regexp will match: "12x34y67g" as well. Also, the first match will catch "1.2.3." (due to the greedy `?`), which may not be what was required.
Al
good point Al. For some reason my \ before the period is not getting printed here
dtmunir
@dtmunir: several of the regex metacharacters also have special meaning to the SO software. You should always enclose regexes in backticks or put them in an indented code block.
Alan Moore
A: 

This is my weird code for do this without regex :-)

public static String[] getTokens(String s) {

 String[] splitted = s.split("\\.");

 //Personally I hate Double.valueOf but I don't know how to avoid it
 String[] result = new String[Double.valueOf(Math.ceil(Double.valueOf(splitted.length) / 3)).intValue()];

 for (int i = 0, j = 0; j < splitted.length; i++, j+=3) {

  //Weird concat
  result[i] = splitted[j] + ( j+1 < splitted.length ? "." + splitted[j+1] : "" ) + ( j+2 < splitted.length ? "." + splitted[j+2] : "" );

 }
 return result;
}
SourceRebels
I did this idea too, but my boss said this string manipulation is more expensive then regex. What do you think?
Joe Ijam
I don't have idea which method is faster/cheaper, probably your boss is right :-)
SourceRebels
+1  A: 
\d+(?:\.\d+){0,2}

This is basically the same as Al's final regex - ((?:\d+\.){0,2}\d+) - but I think it's clearer this way. And there's no need to put parentheses around the whole regex. Assuming you're using Matcher.find() to get the matches, you can use group() or group(0) instead of group(1) to retrieve the matched text.

Alan Moore
This the most simplest result that i want. The result is ;Match 1: 1.2.3Match 2: 4.5.66Match 3: 77.88.99Match 4: 10.52Thank you very much to all for very fast response.
Joe Ijam