views:

123

answers:

6

Similar to a question posted here, am looking for a solution in Java.

That is, how to find the index of nth occurrence of a character/string from a string?

Example: "/folder1/folder2/folder3/". In this case, if I ask for 3rd occurrence of slash (/), it appears before folder3, and I expect to return this index position. My actual intention is to substring it from nth occurrence of a character.

Is there any convenient/ready-to-use method available in Java API or do we need to write a small logic on our own to solve this?

Also,

  1. I quickly searched whether any method is supported for this purpose at Apache Commons Lang's StringUtils, but I don't find any.
  2. Can regular expressions help in this regard?
+4  A: 

Two simple options occur:

  • Use charAt() repeatedly
  • Use indexOf() repeatedly

For example:

public static int nthIndexOf(String text, char needle, int n)
{
    for (int i = 0; i < text.length(); i++)
    {
        if (text.charAt(i) == needle)
        {
            n--;
            if (n == 0)
            {
                return i;
            }
        }
    }
    return -1;
}

That may well not perform as well as using indexOf repeatedly, but it's possibly simpler to get right.

Jon Skeet
+2  A: 
 ([.^/]*/){2}[^/]*(/)

Match anything followed by / two times, then again. The third one is the one you want

The Matcher state can be used to tell where the last / is

Paul
+5  A: 

This should do:

public static int nthOccurrence(String str, char c, int n) {
    int pos = str.indexOf(c, 0);
    while (n-- > 0 && pos != -1)
        pos = str.indexOf(c, pos+1);
    return pos;
}

This snippet of code...

String str = "/folder1/folder2/folder3/";
int index = nthOccurrence(str, '/', 2);
System.out.println(str.substring(index));

... prints:

/folder3/
aioobe
I suspect you want to return pos-1 here, otherwise you'll find the index *past* the nth occurrence. It's fine for then take the substring from that position, but it's probably not a good return value for a general purpose method.
Jon Skeet
Ah, good point. Thanks.
aioobe
@aioobe: +1 - although having to work out that sort of off-by-one error is precisely why my approach doesn't use indexOf :)
Jon Skeet
@Jon, Yeah, for a while I also compared `pos == -1` (after `pos = str.indexOf(c, pos) + 1`).. I thought, damn, it *was* tricky!
aioobe
Shouldn't the 2nd occurrence give the index of `/folder2/folder3/`? That would be the 2nd slash? I would change `n--` to `--n`.
Ishtar
I thought the most convenient thing would be to start counting from 0... depends on your needs of course.
aioobe
+1  A: 
public static int nth(String source, String pattern, int n) {

   int i = 0, pos = 0, tpos = 0;

   while (i < n) {

      pos = source.indexOf(pattern);
      if (pos > -1) {
         source = source.substring(pos+1);
         tpos += pos+1;
         i++;
      } else {
         return -1;
      }
   }

   return tpos - 1;
}
Saul
+1  A: 

You can try something like this:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
      System.out.println(from3rd("/folder1/folder2/folder3/"));
    }

    private static Pattern p = Pattern.compile("(/[^/]*){2}/(.*)");

    public static String from3rd(String in) {
        Matcher m = p.matcher(in);

        if (m.matches())
            return m.group(2);
        else
            return null;
    }
}

Note that I did some assumptions in the regex:

  • the input path is absolute (i.e. starts with "/");
  • you do not need the 3rd "/" in the result.
andcoz
A: 

Another approach:

public static void main(String[] args) {
    String str = "/folder1/folder2/folder3/"; 
    int index = nthOccurrence(str, '/', 3);
    System.out.println(index);
}

public static int nthOccurrence(String s, char c, int occurrence) {
    return nthOccurrence(s, 0, c, 0, occurrence);
}

public static int nthOccurrence(String s, int from, char c, int curr, int expected) {
    final int index = s.indexOf(c, from);
    if(index == -1) return -1;
    return (curr + 1 == expected) ? index : 
        nthOccurrence(s, index + 1, c, curr + 1, expected);
}
Marimuthu Madasamy