Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Andreas Leitgeb Newsgroups: comp.lang.java.programmer Subject: Re: regex replaceAll? Date: Fri, 2 Mar 2018 17:46:07 -0000 (UTC) Organization: A noiseless patient Spider Lines: 51 Message-ID: References: <4a800440-39fe-4684-8369-e6a4e6b9d79f@googlegroups.com> <44c665e1-e965-4e9b-8aa0-72aa20607e63@googlegroups.com> <8c677118-8115-409d-8d3b-396e54b063ae@googlegroups.com> <5e445e98-76e9-4feb-9955-035a6c5a2ed5@googlegroups.com> Reply-To: avl@logic.at Injection-Date: Fri, 2 Mar 2018 17:46:07 -0000 (UTC) Injection-Info: reader02.eternal-september.org; posting-host="43ee598cf591b5380ca4fc229b7a3f4b"; logging-data="23354"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19CO7aruv8wpzhZMXMCcadS" User-Agent: slrn/1.0.2 (Linux) Cancel-Lock: sha1:b03I/PH0Ua4qYqXgCRcPqIqKsZM= Xref: csiph.com comp.lang.java.programmer:38107 Eric Douglas wrote: > out = in.replaceAll("(?<=\\G.*b.*)b", "_"); You might have noticed that the original RE (with spaces) uses \s and \S, and that any single character can only *either* be matched by \s *or* by \S. You can consider \S to be the opposite of \s. The opposite of b isn't ".", but rather "[^b]". Note, that if "b" really should be a possibly longer string, then it's "opposite" will quickly become very ugly with increasing length. That would be a case were you'd better pick an alternative without REs. So, by correcting the "." to "[^b]", you get: out = in.replaceAll("(?<=\\G[^b]*b[^b]*)b", "_"); and to that you can now add the extra pair of non- capturing parens and e.g. "{2}" for n=3 . > The documentation on that says: > (?<=X) X, via zero-width positive lookbehind > (not sure what this did for the original expression here) It makes sure that the "\\G[^b]*b[^b]*" is *not* part of the thing to replace, yet required to exist before the actual match. Your own approach of capturing the "prefix" with parens and substing it into the replacement via $1 looks much cleaner to me, btw. > \G The end of the previous match > (this is what I expect replaceAll to always do) Well, nope. if you do a "ababab".replaceAll("b","_"); you'd want all "b"s replaced, even if not adjacent to the previous one. > \S A non-whitespace character: [^\s] > \s A whitespace character: [ \t\n\x0B\f\r] > X* X, zero or more times > . Any character (may or may not match line terminators) > > Any character includes whitespace? Why does my modified > expression not replace every other "b"? The problem here is, that the "b"s of input string are *also* matched by the ".*", so each single match is likely a bit longer than you expect it to be. I'm pretty sure that it still *did* replace the very last "b".