Как найти n-е вхождение символа в строку? - PullRequest
86 голосов
/ 20 октября 2010

Похоже на опубликованный вопрос здесь , ищу для решения на Java.

То есть, как найти индекс n-го вхождения символа / строки из строки?

Пример:" / folder1 / folder2 / folder3 / ". В этом случае, если я спрашиваю о 3-м появлении косой черты (/), он появляется перед папкой 3, и я ожидаю вернуть эту позицию индекса. Мое истинное намерение состоит в том, чтобы вычеркнуть его из n-го вхождения символа.

Есть ли какой-либо удобный / готовый к использованию метод, доступный в Java API, или нам нужно написать небольшую логику самостоятельно, чтобы решить эту проблему?

Также

  1. Я быстро искал, поддерживается ли какой-либо метод для этой цели в Apache Commons Lang's StringUtils , но я не нашел ни одного.
  2. Могут ли регулярные выражения помочь в этом отношении?

Ответы [ 16 ]

122 голосов
/ 20 октября 2010

Если ваш проект уже зависит от Apache Commons, вы можете использовать StringUtils.ordinalIndexOf, в противном случае вот реализация:

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;
}

Это сообщение было переписано как статья здесь .

55 голосов
/ 01 августа 2012

Я считаю, что самое простое решение для нахождения N-го вхождения строки - это использование StringUtils.ordinalIndexOf () от Apache Commons.

Пример:

StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  == 5
27 голосов
/ 20 октября 2010

Имеются два простых варианта:

  • Используйте charAt() несколько раз
  • Используйте indexOf() несколько раз

Например:

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;
}

Это может не так хорошо работать, как многократное использование indexOf, но, возможно, проще разобраться.

14 голосов
/ 20 октября 2010

Вы можете попробовать что-то вроде этого:

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;
    }
}

Обратите внимание, что я сделал несколько предположений в регулярном выражении:

  • входной путь является абсолютным (т.е. начинается с "/");
  • вам не нужен третий "/" в результате.

В соответствии с просьбой в комментарии я попытаюсь объяснить регулярное выражение: (/[^/]*){2}/([^/]*)

Regular expression visualization

  • /[^/]* - это /, за которым следует [^/]* (любое количество символов, которые не являются /),
  • (/[^/]*) группирует предыдущее выражение в одну сущность.Это 1 группа выражений,
  • (/[^/]*){2} означает, что группа должна совпадать {2} раз,
  • [^/]* - это снова любое количество символов, которыене /,
  • ([^/]*) группирует предыдущее выражение в одну сущность.Это 2 ая группа выражения.

Таким образом, вам нужно только получить подстроку, которая соответствует 2-й группе: return m.group(2);

Изображение предоставлено Debuggex

8 голосов
/ 24 октября 2012

Я внес несколько изменений в ответ aioobe, получил n-ю версию lastIndexOf и исправил некоторые проблемы с NPE. Смотрите код ниже:

public int nthLastIndexOf(String str, char c, int n) {
        if (str == null || n < 1)
            return -1;
        int pos = str.length();
        while (n-- > 0 && pos != -1)
            pos = str.lastIndexOf(c, pos - 1);
        return pos;
}
5 голосов
/ 20 октября 2010
 ([.^/]*/){2}[^/]*(/)

Совпадение с чем угодно, затем / два раза, затем снова.Третий - тот, который вам нужен

Состояние Matcher может быть использовано для определения, где находится последний /

3 голосов
/ 24 января 2014

В настоящее время есть поддержка Apache Commons Lang's StringUtils ,

Это примитив:

int org.apache.commons.lang.StringUtils.ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal)

для вашей проблемы вы можетекодируйте следующее: StringUtils.ordinalIndexOf(uri, "/", 3)

Вы также можете найти последнее n-е вхождение символа в строке с помощью метода lastOrdinalIndexOf .

3 голосов
/ 20 октября 2010
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;
}
2 голосов
/ 05 августа 2015

Этот ответ улучшает ответ @aioobe. В этом ответе исправлены две ошибки.
1. n = 0 должно вернуть -1.
2. n-й случай вернул -1, но сработал n-1-й случай.

Попробуйте это!

    public int nthOccurrence(String str, char c, int n) {
    if(n <= 0){
        return -1;
    }
    int pos = str.indexOf(c, 0);
    while (n-- > 1 && pos != -1)
        pos = str.indexOf(c, pos+1);
    return pos;
}
2 голосов
/ 21 октября 2010

Другой подход:

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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...