9

I need to change a piece of code which includes this:

string.indexOf("bc")

How can this be changed by a solution that skips the occurrence of "bc" if it is preceded by the letter "a".

I don't want to find these:

abc

but only:

xbc

where x can be anything but a (even empty).

I think I could just put in a condition that checks if the index i-1 == a, and if true call the indexOf method again. But I don't think that would result in very beautiful code.

How would a solution that uses regular expressions look like?

Edit: Just a hint after seeing some responses. It would be nice to get not only the regular expression, but also the required API calls to find the index.

Scaramouche
  • 3,188
  • 2
  • 20
  • 46
Hans Wiener
  • 129
  • 1
  • 1
  • 8

4 Answers4

19

As requested a more complete solution:

    /** @return index of pattern in s or -1, if not found */
public static int indexOf(Pattern pattern, String s) {
    Matcher matcher = pattern.matcher(s);
    return matcher.find() ? matcher.start() : -1;
}

call:

int index = indexOf(Pattern.compile("(?<!a)bc"), "abc xbc");
Arne
  • 2,106
  • 12
  • 9
  • Well, my Edit was more a response to the answers that only contained a single regular expression. But thanks anyway, this looks nice. – Hans Wiener Jun 26 '12 at 20:44
  • if you wanted to do indexing on top of it you could do: public static int indexOf(String regex, String s, int index) { Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(s); return matcher.find(index) ? matcher.start() : -1; } ... int index = indexOf("(?<!a)bc", "abc xbc", 2); – Andre Nel Nov 01 '17 at 11:30
5

You could use a regex with a negative lookbehind:

(?<!a)bc

Unfortunately to reproduce .indexOf with Regex in Java is still a mess:

Pattern pattern = Pattern.compile("(?!a)bc");
Matcher matcher = pattern.matcher("abc xbc");
if (matcher.find()) {
    return matcher.start();
}
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • Negative lookbehind seems to hit the nail pretty much. Too bad there isnt a .indexof(Regex) in the API. – Hans Wiener Jun 26 '12 at 19:25
  • @HansWiener sorry it should be `matcher.find()` (see? It's a mess :) ). – kennytm Jun 26 '12 at 19:46
  • Ah its just a typo, which version should I accept now? Thers also a typo in the regex expression (missing <) – Hans Wiener Jun 26 '12 at 19:46
  • Honestly what is the point of finding a match to a reg exp if then there is no way to retrieve the starting or ending index of the pattern found in the String? This is why I refuse to use Pattern and Matcher classes. It's too cryptic and way more frustrating and time-wasting than helpful. You gotta scrub through the String char by char. You complete your objective much faster with much less frustration I promise – JamisonMan111 Jul 02 '18 at 23:45
2

To add to Arne's answer - if you wanted to also add indexing:

public static int indexOf(String regex, String s, int index)
{
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(s);
    return matcher.find(index) ? matcher.start() : -1;
}

call:

int index = indexOf("(?<!a)bc", "abc xbc", 2);
Andre Nel
  • 432
  • 2
  • 9
1

Use regex to find the String that matches your criteria, and then find the index of that String.

int index = -1;
Pattern p = Pattern.compile("[^Aa]?bc");
Matcher m = p.matcher(string);
if (m.find()) {
    index = m.start();
}

Something like this. Where 'string' is the text you're searching and 'index' holds the location of the string that is found. (index will be -1 if not found.) Also note that the pattern is case sensitive unless you set a flag.

Roddy of the Frozen Peas
  • 14,380
  • 9
  • 49
  • 99