Индексы всех вхождений символа в строку

101

Следующий код напечатает 2

String word = "bannanas";
String guess = "n";
int index;
System.out.println( 
    index = word.indexOf(guess)
);

Я хотел бы знать, как получить все индексы «n» («угадать») в строке «bannanas»

Ожидаемый результат: [2,3,5]

Труфа
источник

Ответы:

164

Это должно вывести список позиций без -1в конце , что решение Питера Lawrey в уже имел.

int index = word.indexOf(guess);
while (index >= 0) {
    System.out.println(index);
    index = word.indexOf(guess, index + 1);
}

Это также можно сделать в виде forцикла:

for (int index = word.indexOf(guess);
     index >= 0;
     index = word.indexOf(guess, index + 1))
{
    System.out.println(index);
}

[Примечание: если длина guessможет быть больше одного символа, то можно, проанализировав guessстроку, выполнить цикл wordбыстрее, чем это делают указанные выше циклы. Эталоном для такого подхода является алгоритм Бойера-Мура . Однако условий, которые способствовали бы использованию такого подхода, похоже, нет.]

Тед Хопп
источник
28

Попробуйте следующее (что теперь не выводит -1 в конце!)

int index = word.indexOf(guess);
while(index >= 0) {
   System.out.println(index);
   index = word.indexOf(guess, index+1);
}
Питер Лоури
источник
1
вы всегда печатаете -1 в конце
lukastymo
@Peter Большое спасибо за ваш ответ, кажется, что это правильно, но на самом деле это мой первый день с Java, поэтому я немного смущен окончательным результатом, похоже, в конце получается -1, а я не Я понимаю, почему! Спасибо!!
Trufa
@Trufa: всегда выводит -1 в конце, потому что indexOfвозвращает -1, если символ не найден.
ColinD
@Trufa - причина, по которой он печатается -1в конце, заключается в том, что doцикл выполняет тело, а затем обнаруживает его index == -1в завершении while.
Тед Хопп
@ColinD, эту часть я получаю, чего я не понимаю, так это того, что происходит с функцией, чтобы это произошло, он "зацикливается" на слове, ища вхождение символа, и до тех пор, пока это не произойдет, он больше не сможет найти правильного ? и печатает этот последний индекс того, что не найдено (-1), это то, что происходит? (Я не знаю, правильно ли это вышло)
Trufa
7
String string = "bannanas";
ArrayList<Integer> list = new ArrayList<Integer>();
char character = 'n';
for(int i = 0; i < string.length(); i++){
    if(string.charAt(i) == character){
       list.add(i);
    }
}

Результат будет использоваться так:

    for(Integer i : list){
        System.out.println(i);
    }

Или как массив:

list.toArray();
POSIX_ME_HARDER
источник
3
int index = -1;
while((index = text.indexOf("on", index + 1)) >= 0) {
   LOG.d("index=" + index);
}
urSus
источник
3

Функционально это можно сделать в Java 9, используя регулярное выражение:

Pattern.compile(Pattern.quote(guess)) // sanitize input and create pattern
            .matcher(word) // create matcher
            .results()     // get the MatchResults, Java 9 method
            .map(MatchResult::start) // get the first index
            .collect(Collectors.toList()) // collect found indices into a list
    );

Вот решение Kotlin для добавления этой логики в качестве новых новых методов в CharSequenceAPI с использованием метода расширения:

 // Extension method
fun CharSequence.indicesOf(input: String): List<Int> =
    Regex(Pattern.quote(input)) // build regex
        .findAll(this)          // get the matches
        .map { it.range.first } // get the index
        .toCollection(mutableListOf()) // collect the result as list

// call the methods as
"Banana".indicesOf("a") // [1, 3, 5]
Pavneet_Singh
источник
1
String word = "bannanas";

String guess = "n";

String temp = word;

while(temp.indexOf(guess) != -1) {
     int index = temp.indexOf(guess);
     System.out.println(index);
     temp = temp.substring(index + 1);
}
asgs
источник
Общая идея верна, но word.substring(word)не компилируется. : P
Питер Лоури
1
По-прежнему есть проблема: он печатает непрерывно 2.
POSIX_ME_HARDER
Гоша, мне нужно javac все, что я публикую здесь.
asgs
0
    String input = "GATATATGCG";
    String substring = "G";
    String temp = input;
    String indexOF ="";
    int tempIntex=1;

    while(temp.indexOf(substring) != -1)
    {
        int index = temp.indexOf(substring);
        indexOF +=(index+tempIntex)+" ";
        tempIntex+=(index+1);
        temp = temp.substring(index + 1);
    }
    Log.e("indexOf ","" + indexOF);
Идрис Йылдыз
источник
0

Кроме того, если вы хотите найти все индексы String в String.

int index = word.indexOf(guess);
while (index >= 0) {
    System.out.println(index);
    index = word.indexOf(guess, index + guess.length());
}
Элитный VIP
источник
Это интересно тем, что порождает двусмысленность в значении «все вхождения». Если guess было "aba"и wordбыло "ababa", неясно, guessпроисходит ли это один или два раза word. (Я имею в виду, ясно, что можно найти guessначало в двух различных позициях, но поскольку вхождения перекрываются, неясно, следует ли считать их оба.) Этот ответ исходит из того, что перекрывающиеся вхождения не считаются отдельными. Конечно, поскольку формулировка OP настоятельно предполагает, что guessдлина всегда будет равна 1, двусмысленности не возникает.
Тед Хопп,
0

У меня тоже была эта проблема, пока я не придумал этот метод.

public static int[] indexesOf(String s, String flag) {
    int flagLen = flag.length();
    String current = s;
    int[] res = new int[s.length()];
    int count = 0;
    int base = 0;
    while(current.contains(flag)) {
        int index = current.indexOf(flag);
        res[count] = index + base;
        base += index + flagLen;
        current = current.substring(current.indexOf(flag) + flagLen, current.length());
        ++ count;
    }
    return Arrays.copyOf(res, count);
}

Этот метод можно использовать для поиска индексов любого флага любой длины в строке, например:

public class Main {

    public static void main(String[] args) {
        int[] indexes = indexesOf("Hello, yellow jello", "ll");

        // Prints [2, 9, 16]
        System.out.println(Arrays.toString(indexes));
    }

    public static int[] indexesOf(String s, String flag) {
        int flagLen = flag.length();
        String current = s;
        int[] res = new int[s.length()];
        int count = 0;
        int base = 0;
        while(current.contains(flag)) {
            int index = current.indexOf(flag);
            res[count] = index + base;
            base += index + flagLen;
            current = current.substring(current.indexOf(flag) + flagLen, current.length());
            ++ count;
        }
        return Arrays.copyOf(res, count);
    }
}
Ян С.
источник
0

Я придумал класс для разделения струн. В конце предоставляется небольшой тест.

SplitStringUtils.smartSplitToShorterStrings(String str, int maxLen, int maxParts) будет разделен пробелами без разрыва слов, если это возможно, а если нет, разделится по индексам в соответствии с maxLen.

Другие методы, позволяющие управлять разделением: bruteSplitLimit(String str, int maxLen, int maxParts), spaceSplit(String str, int maxLen, int maxParts).

public class SplitStringUtils {

  public static String[] smartSplitToShorterStrings(String str, int maxLen, int maxParts) {
    if (str.length() <= maxLen) {
      return new String[] {str};
    }
    if (str.length() > maxLen*maxParts) {
      return bruteSplitLimit(str, maxLen, maxParts);
    }

    String[] res = spaceSplit(str, maxLen, maxParts);
    if (res != null) {
      return res;
    }

    return bruteSplitLimit(str, maxLen, maxParts);
  }

  public static String[] bruteSplitLimit(String str, int maxLen, int maxParts) {
    String[] bruteArr = bruteSplit(str, maxLen);
    String[] ret = Arrays.stream(bruteArr)
          .limit(maxParts)
          .collect(Collectors.toList())
          .toArray(new String[maxParts]);
    return ret;
  }

  public static String[] bruteSplit(String name, int maxLen) {
    List<String> res = new ArrayList<>();
    int start =0;
    int end = maxLen;
    while (end <= name.length()) {
      String substr = name.substring(start, end);
      res.add(substr);
      start = end;
      end +=maxLen;
    }
    String substr = name.substring(start, name.length());
    res.add(substr);
    return res.toArray(new String[res.size()]);
  }

  public static String[] spaceSplit(String str, int maxLen, int maxParts) {
    List<Integer> spaceIndexes = findSplitPoints(str, ' ');
    List<Integer> goodSplitIndexes = new ArrayList<>();
    int goodIndex = -1; 
    int curPartMax = maxLen;
    for (int i=0; i< spaceIndexes.size(); i++) {
      int idx = spaceIndexes.get(i);
      if (idx < curPartMax) {
        goodIndex = idx;
      } else {
        goodSplitIndexes.add(goodIndex+1);
        curPartMax = goodIndex+1+maxLen;
      }
    }
    if (goodSplitIndexes.get(goodSplitIndexes.size()-1) != str.length()) {
      goodSplitIndexes.add(str.length());
    }
    if (goodSplitIndexes.size()<=maxParts) {
      List<String> res = new ArrayList<>();
      int start = 0;
      for (int i=0; i<goodSplitIndexes.size(); i++) {
        int end = goodSplitIndexes.get(i);
        if (end-start > maxLen) {
          return null;
        }
        res.add(str.substring(start, end));
        start = end;
      }
      return res.toArray(new String[res.size()]);
    }
    return null;
  }


  private static List<Integer> findSplitPoints(String str, char c) {
    List<Integer> list = new ArrayList<Integer>();
    for (int i = 0; i < str.length(); i++) {
      if (str.charAt(i) == c) {
        list.add(i);
      }
    }
    list.add(str.length());
    return list;
  }
}

Простой тестовый код:

  public static void main(String[] args) {
    String [] testStrings = {
        "123",
        "123 123 123 1123 123 123 123 123 123 123",
        "123 54123 5123 513 54w567 3567 e56 73w45 63 567356 735687 4678 4678 u4678 u4678 56rt64w5 6546345",
        "1345678934576235784620957029356723578946",
        "12764444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444",
        "3463356 35673567567 3567 35 3567 35 675 653 673567 777777777777777777777777777777777777777777777777777777777777777777"
    };

    int max = 35;
    int maxparts = 2;


    for (String str : testStrings) {
      System.out.println("TEST\n    |"+str+"|");
      printSplitDetails(max, maxparts);
      String[] res = smartSplitToShorterStrings(str, max, maxparts);
      for (int i=0; i< res.length;i++) {
        System.out.println("  "+i+": "+res[i]);
      }
      System.out.println("===========================================================================================================================================================");
    }

  }

  static void printSplitDetails(int max, int maxparts) {
    System.out.print("  X: ");
    for (int i=0; i<max*maxparts; i++) {
      if (i%max == 0) {
        System.out.print("|");
      } else {
        System.out.print("-");
      }
    }
    System.out.println();
  }
Дариуш
источник
0

Это решение для Java 8.

public int[] solution (String s, String subString){
        int initialIndex = s.indexOf(subString);
        List<Integer> indexList = new ArrayList<>();
        while (initialIndex >=0){
            indexList.add(initialIndex);
            initialIndex = s.indexOf(subString, initialIndex+1);
        }
        int [] intA = indexList.stream().mapToInt(i->i).toArray();
        return intA;
    }
Бамиделе Алегбе
источник
-1

Это можно сделать путем итерации myStringи сдвига fromIndexпараметра в indexOf():

  int currentIndex = 0;

  while (
    myString.indexOf(
      mySubstring,
      currentIndex) >= 0) {

    System.out.println(currentIndex);

    currentIndex++;
  }
Зон
источник
Вы хоть пробовали запустить этот код? Он будет распечатывать каждую позицию (0, 1, 2, ...) до индекса последнего вхождения mySubstring, независимо от того, mySubstringможно ли найти в каждой позиции. Совсем не то, что хотел OP ..
Тед Хопп,
-4

Попробуй это

String str = "helloslkhellodjladfjhello";
String findStr = "hello";

System.out.println(StringUtils.countMatches(str, findStr));
Викас Кумбхар
источник
Это хорошо для подсчета экземпляров подстроки в более крупной строке, но не возвращает индексы совпадений.
fiveclubs
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа.
Nic3500,
Это не отвечает на вопрос. Вопрос требует список всех индексов
шеу