1

This code totally runs when I am applying it outside android, that is, in a pure java enviroment. (There is a link that says it is a doublicate of the question, but its not) I want to know why it runs in java without android, but crashes in android.

String[] ar = new String[iters];
ar = myStr.split("(?<=\\G.{16})");

However, when I apply the same in android enviroment, I get the following exception

04-13 13:50:22.255: E/AndroidRuntime(2147): FATAL EXCEPTION: main
04-13 13:50:22.255: E/AndroidRuntime(2147): java.util.regex.PatternSyntaxException: Look-behind pattern matches must have a bounded maximum length near index 12:
04-13 13:50:22.255: E/AndroidRuntime(2147): (?<=\G.{16})
tony9099
  • 4,567
  • 9
  • 44
  • 73
  • 1
    Avoid `(?<=\\G.whatever)` approach. Even if it works in standard Java, it does it against regex engine assumptions that look-behind needs to have maximal length and we don't know what length `\\G` represents. So as you see this behaviour can change in newer versions of Java (or Java-like environments like Android). Instead use `Pattern` and `Matcher` classes like `Matcher m = Pattern.compile(".{16}").matcher(myStr); while (m.find){ String s = m.group(); ... }` – Pshemo Apr 13 '15 at 11:12
  • @Pshemo can you provide a working example for the above using those? – tony9099 Apr 13 '15 at 11:16
  • OK, I posted answer with example of how you can rewrite your code using Pattern and Matcher classes. I didn't add code responsible for storing each token in array since I don't know if you will need it really because you may already handle each token returned by `m.group()` as you want (in my code I print it, but you can store it in some List like ArrayList and reuse later). – Pshemo Apr 13 '15 at 11:29
  • @Pshemo thanks a lot. indeed. no need for arrays as I can use them directly (which I'm doing) thanks – tony9099 Apr 13 '15 at 15:16

1 Answers1

5

Possible reason:

It looks like a bug of Java version which your Android is using, which was corrected in later Java versions.

\G can be considered as anchor which represents either

  • end of previous match
  • start of the string (if no match was found yet)

and as any anchor it is zero-length.

I suspect that main part of that bug is that \G is seen by look-behind as entire previous match, not its end, and since previous match could have any length look-behind complains about it because it can't determine obvious maximal length.

Way around.

Avoid split("(?<=\\Gwhatever)").

Instead of finding delimiters, use Matcher class to find() things you want to get from text. So your code can look like:

String myStr = "0123456789012345678901234567890123456789012345678901234567890123456789";

Matcher m = Pattern.compile(".{1,16}").matcher(myStr);
while (m.find()) {
    String s = m.group();
    //do what you want with current token stored in `s`
    System.out.println(s);
}

Output:

0123456789012345
6789012345678901
2345678901234567
8901234567890123
456789
Community
  • 1
  • 1
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • Good solution, but I disagree with your analysis. `\G` is a zero-width assertion; it matches the position where the previous match ended. It doesn't consume any characters, so it can't affect the length of what's matched inside the lookbehind. `\G` in lookbehinds has always worked in Java, and it *should* work in Android. – Alan Moore May 05 '16 at 18:01
  • @AlanMoore I also though that it *should* work in a way you mention, but I remember having problem which made me little skeptic about it. I don't remember in which Java version was it precisely nor how regex looked like, but there was case where I had `(?<=something)` and it worked fine, but adding `\G` like `(?<=\Gsomething)` caused `Look-behind group does not have an obvious maximum length...` problem. So since `something` part had obvious maximal length it looked like `\G` may be seen as non-zero-width. – Pshemo May 05 '16 at 19:06