4

I would think this should return "state,country" but it's returning "country"

System.out.println("city,state,country".replaceAll("(.*,)?", ""));

Why is it working this way, and how do I make it return "state,country". I want this answer as a regex.

Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356

5 Answers5

16
  1. if you want to make .* to be non-greedy you need to add ? right after *.
  2. replaceAll will replace all occurrences of matching parts, so you should probably use replaceFirst

try

System.out.println("city,state,country".replaceFirst(".*?,", ""));

output:

state,country

If you can't use replaceFirst and need to stay with replaceAll then @Reimeus answer is probably what you are looking for.

Community
  • 1
  • 1
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • This will work if replaceFirst is only used, but otherwise will wipe out city and state. –  Apr 29 '13 at 18:37
  • @0A0D I am not sure what you are trying to say. Could you explain it more? – Pshemo Apr 29 '13 at 18:43
  • It will match `city,state,` then replace it with nothing and just give him `country`.. I think: http://regexr.com?34nck if you use replaceAll –  Apr 29 '13 at 18:44
  • @0A0D Yes this regex will match `city,` and `state,` but `replaceFirst` will only replace first match, so `city,` will be replaced with `""` and `state,` will be unchanged. – Pshemo Apr 29 '13 at 18:47
  • 1
    Yep, if you use replaceFirst :) .. other answerers were using replaceAll –  Apr 29 '13 at 18:48
  • @0A0D OK, so there is nothing wrong with my answer. I am just curious why I got -1. Probably some accident :) – Pshemo Apr 29 '13 at 18:50
  • I'd like the answer to use `replaceAll` because I can see being in situations where I couldn't use `replaceFirst` – Daniel Kaplan Apr 29 '13 at 20:27
  • 1
    @tieTYT then you should add `^` anchor at start of regex to show that matching part must be placed at start of the input string, just like Reimeus showed in his answer. – Pshemo Apr 29 '13 at 20:30
7

As the name suggests, replaceAll replaces all matching groups. You need to be more specific where the group is matched. To specify the first matching group you can specify the start of String ^ as an anchor:

"city,state,country".replaceAll("^(.*?,)", "")
Reimeus
  • 158,255
  • 15
  • 216
  • 276
4

You're capturing any group ending in a comma, not just one and that's why it doesn't currently work.

System.out.println("city,state,country".replaceAll("^[^,]*+,", ""));
Jean-Bernard Pellerin
  • 12,556
  • 10
  • 57
  • 79
  • 1
    +1 - Nice use of negated character classes as an alternate to reluctant qualifier. – Alex Apr 29 '13 at 18:46
  • Agreed with @Alex, that's a nice aspect of your answer to point out. You can go farther and make it a "possessive" greedy match, i.e. `^[^,]*+,` which indicates that backtracking will never be needed. – Joel Nelson Apr 29 '13 at 18:57
1

The ? non-greedy flag can only be used after a + or *, in your context, it is a 0-or-1 match.

You want

System.out.println("city,state,country".replaceAll("(.*?,)", ""));
rolfl
  • 17,539
  • 7
  • 42
  • 76
1

Try with this expression:

^(.*?,)

or like that:

System.out.println("city,state,country".replaceAll("(.*?,)((?:.*?,)+)", "$2"));
Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
  • 1
    Not sure why you were downvoted. I did learn from this answer that group references are accepted on the replacement side, +1 from me. – Joel Nelson Apr 29 '13 at 18:47