Indeksy wszystkich wystąpień znaku w ciągu

101

Poniższy kod spowoduje wydrukowanie 2

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

Chciałbym wiedzieć, jak uzyskać wszystkie indeksy „n” („zgadnij”) w ciągu „banany”

Oczekiwany wynik to: [2,3,5]

Trufa
źródło

Odpowiedzi:

162

To powinno wydrukować listę pozycji bez -1na koniec, że rozwiązanie Petera Lawrey za nie miałem.

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

Można to również zrobić jako forpętlę:

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

[Uwaga: jeśli guessmoże być dłuższy niż pojedynczy znak, analizując guessłańcuch, można wykonać pętlę wordszybciej niż powyższe pętle. Wzorcem dla takiego podejścia jest algorytm Boyera-Moore'a . Wydaje się jednak, że nie istnieją warunki, które sprzyjałyby zastosowaniu takiego podejścia.]

Ted Hopp
źródło
28

Spróbuj wykonać następujące czynności (co nie powoduje teraz wypisania -1 na końcu!)

int index = word.indexOf(guess);
while(index >= 0) {
   System.out.println(index);
   index = word.indexOf(guess, index+1);
}
Peter Lawrey
źródło
1
zawsze drukujesz -1 na końcu
lukastymo
@Peter Dziękuję bardzo za odpowiedź, wydaje się, że to prawda, ale tak naprawdę to mój pierwszy dzień z Javą, więc jestem trochę zdezorientowany końcowym wynikiem, wydaje się, że na końcu wyświetla -1 i nie robię całkiem rozumiem, dlaczego! dzięki!!
Trufa,
@Trufa: Zawsze wypisuje -1 na końcu, ponieważ indexOfzwraca -1, gdy znak nie zostanie znaleziony.
ColinD
@Trufa - powodem, dla którego wypisuje się -1na końcu, jest to, że dopętla wykonuje treść, a następnie odkrywa to index == -1w zakończeniu while.
Ted Hopp,
@ColinD ta część, którą dostaję, nie rozumiem, co się dzieje z funkcją, aby to się stało, "zapętla się" przez słowo, szukając wystąpienia postaci i dopóki to nie jest, nie może znaleźć więcej właściwego ? i wypisuje ostatni indeks tego, że nie znaleziono (-1), czy to się dzieje? (Nie wiem, czy to wyszło dobrze)
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);
    }
}

Wynik zostałby użyty w następujący sposób:

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

Lub jako tablica:

list.toArray();
POSIX_ME_HARDER
źródło
4

W Javie9 można skorzystać z iterate(int seed, IntPredicate hasNext,IntUnaryOperator next):

List<Integer> indexes = IntStream
          .iterate(word.indexOf(c), index -> index >= 0, index -> word.indexOf(c, index + 1))
          .boxed()
          .collect(Collectors.toList());
System.out.printlnt(indexes);
Naman
źródło
3
int index = -1;
while((index = text.indexOf("on", index + 1)) >= 0) {
   LOG.d("index=" + index);
}
urSus
źródło
3

Można to zrobić w funkcjonalny sposób w Javie 9 używając wyrażenia regularnego:

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

Oto rozwiązanie Kotlin umożliwiające dodanie tej logiki jako nowej nowej metody do CharSequenceinterfejsu API przy użyciu metody rozszerzenia:

 // 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
źródło
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
źródło
Ogólny pomysł jest poprawny, ale word.substring(word)się nie skompiluje. : P
Peter Lawrey
1
Nadal występuje problem: drukuje w sposób ciągły 2.
POSIX_ME_HARDER
Ojej, muszę javac wszystko, co tu zamieszczam.
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);
idris yıldız
źródło
0

Ponadto, jeśli chcesz znaleźć wszystkie indeksy String w String.

int index = word.indexOf(guess);
while (index >= 0) {
    System.out.println(index);
    index = word.indexOf(guess, index + guess.length());
}
Elite Vip
źródło
Jest to interesujące, ponieważ rodzi niejednoznaczność w znaczeniu „wszystkich zdarzeń”. Jeśli guess było "aba"i wordbyło "ababa", nie jest jasne, czy guesszdarzyło się to raz czy dwa razy word. (To znaczy, jasne jest, że można znaleźć guesspoczątek w dwóch różnych pozycjach, ale ponieważ wystąpienia nakładają się, nie jest jasne, czy należy je policzyć.) W tej odpowiedzi przyjęto pogląd, że nakładające się wystąpienia nie są liczone jako odrębne. Oczywiście, ponieważ sformułowanie OP zdecydowanie sugeruje, że guesszawsze będzie miał długość 1, nie ma dwuznaczności.
Ted Hopp
0

Ja też miałem ten problem, dopóki nie wymyśliłem tej metody.

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

Tej metody można użyć do znalezienia indeksów dowolnej flagi o dowolnej długości w ciągu, na przykład:

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);
    }
}
Ian S.
źródło
0

Wymyślona przeze mnie klasa do dzielenia strun. Na końcu znajduje się krótki test.

SplitStringUtils.smartSplitToShorterStrings(String str, int maxLen, int maxParts) jeśli to możliwe, podzieli spacje bez łamania słów, a jeśli nie, podzieli według indeksów zgodnie z maxLen.

Inne metody kontroli podziału: 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;
  }
}

Prosty kod testowy:

  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();
  }
Dariusz
źródło
0

To jest rozwiązanie 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;
    }
Bamidele Alegbe
źródło
-1

Można to zrobić poprzez iterację myStringi zmianę fromIndexparametrów w indexOf():

  int currentIndex = 0;

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

    System.out.println(currentIndex);

    currentIndex++;
  }
Zon
źródło
Czy próbowałeś nawet uruchomić ten kod? Wypisze każdą pozycję (0, 1, 2, ...) aż do indeksu ostatniego wystąpienia mySubstring, niezależnie od tego, czy mySubstringmożna go znaleźć na każdej pozycji. Zupełnie nie to, czego chciał OP ...
Ted Hopp
-4

Spróbuj tego

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

System.out.println(StringUtils.countMatches(str, findStr));
Vikas Kumbhar
źródło
Jest to dobre do liczenia wystąpień podciągu w większym ciągu, ale nie zwraca indeksów dopasowań.
fiveclubs 15.07.15
Chociaż ten kod może odpowiedzieć na pytanie, dostarczenie dodatkowego kontekstu dotyczącego tego, jak i / lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi.
Nic3500
To nie odpowiada na pytanie. Pytanie wymaga listy wszystkich wskaźników
sheu