tags:

views:

75

answers:

3

I want to replace a single <, but not <<, using a Java regexp (so I'm working with String.replaceAll()). Right now I have

([^<]|^)<([^<]|$)

which works in Python, but not Java. I have also tried negative look-around, with something like

(?<!<)<(?!<)

However, all my current attempts match << as well. Am I doing something wrong? Is there any Java-specifics here I don't know about?

A: 

Perhaps you are using the wrong replacement?

\n is only used in backrefering to the capture group on the pattern side. You have to use $n to use it on the replacement side.

See http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Matcher.html#replaceAll%28java.lang.String%29 for the documention on this.

Sven Lilienthal
+1  A: 

Your first regex contains a character class ([^<]|^). That's a positive match, so whatever gets caught in the character class will be replaced by replaceAll().

Your second regex only uses lookaround, which only verifies a condition, and does not match:

(?<!<)<(?!<)

That one works fine for me: it does not match <<. Perhaps you can post a code snippet and some input/output that does not behave as you'd expect?

Andomar
Yeah, the first replacement is really replaceAll("([^<]|^)<([^<]|$)", "\\1(\\2")But the second one actually works fine for you with replaceAll? I have replaceAll("(?<!<)<(?!<)", "(") which replaces << with (( in all test inputs. Maybe I need to use Matcher and Pattern instead?
tobiasvl
@tobiasvl: I did a test using a regex simulator in Java mode, which said it worked fine. Perhaps replaceAll works differently from Matcher? Can't hurt to try it
Andomar
I've tested this in Java, not a simulator, and it works as expected: `<` is replaced and `<<` is left alone. And it doesn't matter whether I use `String#replaceAll` or `Matcher#replaceAll`, the result is the same.
Alan Moore
BTW, if you're really using `"\\1(\\2"` as the replacement string, you should be getting `1(2` for output. The correct syntax would be `"$1($2"`.
Alan Moore
+1  A: 

If you want to replace a single "<" with an "X" say, do this:

String test = "hello << world < blah < blah << blah";

String _test = test.replaceAll("(^|[^<])<([^<]|$)", "$1X$2");

System.out.println(_test);

Gives you this:

hello << world X blah X blah << blah

Edit Updated to match at beginning and end of line

Richard
"(\A|[^<])<([^<]|\Z)" to also get the occurences at the start and end of the string.
Svante
Would this work for 'a<b<c'?
Mark Byers
Hi Svante - yes I just adjusted to take care of beginning, end of lines
Richard
As Mark suggested, it doesn't work for `a<b<c` -- it only replaces the first `<`. But the lookaround version the OP posted does work.
Alan Moore
confirmed - it doesn't work for "a<b<c", although not sure why
Richard
`(^|[^<])` would need to match the `b` the second time around, but that was already consumed by `([^<]|$)` when the first replacement was done.
Alan Moore