Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find nth occurrence of character in a string?

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?
like image 506
Gnanam Avatar asked Oct 20 '10 09:10

Gnanam


4 Answers

If your project already depends on Apache Commons you can use StringUtils.ordinalIndexOf, otherwise, here's an implementation:

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

This post has been rewritten as an article here.

like image 82
aioobe Avatar answered Nov 12 '22 02:11

aioobe


I believe the easiest solution for finding the Nth occurrence of a String is to use StringUtils.ordinalIndexOf() from Apache Commons.

Example:

StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  == 5
like image 40
Al Belsky Avatar answered Nov 12 '22 02:11

Al Belsky


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.

like image 29
Jon Skeet Avatar answered Nov 12 '22 00:11

Jon Skeet


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.

As requested in a comment, I'll try to explain the regex: (/[^/]*){2}/([^/]*)

Regular expression visualization

  • /[^/]* is a / followed by [^/]* (any number of characters that are not a /),
  • (/[^/]*) groups the previous expression in a single entity. This is the 1st group of the expression,
  • (/[^/]*){2} means that the group must match extactly {2} times,
  • [^/]* is again any number of characters that are not a /,
  • ([^/]*) groups the previos expression in a single entity. This is the 2nd group of the expression.

This way you have only to get the substring that matches the 2nd group: return m.group(2);

Image courtesy by Debuggex

like image 15
andcoz Avatar answered Nov 12 '22 01:11

andcoz