Indici di tutte le occorrenze di carattere in una stringa


101

Verrà stampato il codice seguente 2

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

Vorrei sapere come ottenere tutti gli indici di "n" ("guess") nella stringa "bannanas"

Il risultato atteso sarebbe: [2,3,5]

Risposte:


162

Questo dovrebbe stampare l'elenco delle posizioni senza -1la fine che ha avuto la soluzione di Peter Lawrey .

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

Può anche essere fatto come un forciclo:

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

[Nota: se guesspuò essere più lungo di un singolo carattere, allora è possibile, analizzando la guessstringa, scorrere wordpiù velocemente di quanto non facciano i cicli precedenti. Il punto di riferimento per un tale approccio è l' algoritmo di Boyer-Moore . Tuttavia, le condizioni che favorirebbero l'utilizzo di un tale approccio non sembrano essere presenti.]


28

Prova quanto segue (che non stampa -1 alla fine ora!)

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

1
stampa sempre -1 alla fine
lukastymo

@Peter Grazie mille per la tua risposta, sembra giusto, ma in realtà è il mio primo giorno con Java, quindi sono un po 'confuso dal risultato finale, sembra che alla fine produca -1 e non lo so Non capisco bene perché! Grazie!!
Trufa

@Trufa: stampa sempre -1 alla fine perché indexOfrestituisce -1 quando il carattere non viene trovato.
ColinD

@Trufa - il motivo per cui stampa -1alla fine è che il dociclo esegue il corpo e poi lo scopre index == -1alla fine while.
Ted Hopp

@ColinD quella parte che ricevo, quello che non capisco è cosa succede con la funzione perché ciò accada, "scorre" attraverso la parola cercando l'occorrenza del personaggio e fino a quando non è più giusto ? e stampa quest'ultimo indice di quello non trovato (-1), è quello che sta succedendo? (Non so se sia uscito bene)
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);
    }
}

Il risultato sarebbe usato in questo modo:

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

O come array:

list.toArray();


3
int index = -1;
while((index = text.indexOf("on", index + 1)) >= 0) {
   LOG.d("index=" + index);
}

2

Questo può essere fatto in modo funzionale con Java 9 usando l'espressione regolare:

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

Ecco la soluzione Kotlin per aggiungere questa logica come un nuovo un nuovo metodo CharSequencenell'API utilizzando il metodo di estensione:

 // 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]

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

L'idea generale è giusta, ma word.substring(word)non verrà compilata. : P
Peter Lawrey

1
Ha ancora un problema: stampa continuamente 2.
POSIX_ME_HARDER

Accidenti, ho bisogno di javac tutto quello che posto qui.
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

Inoltre, se vuoi trovare tutti gli indici di una stringa in una stringa.

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

Ciò è interessante in quanto solleva un'ambiguità nel significato di "tutte le occorrenze". Se guess era "aba"ed wordera "ababa", non è chiaro se si guessverifica una o due volte word. (Voglio dire, è chiaro che si può trovare l' guessinizio da due posizioni distinte, ma poiché le occorrenze si sovrappongono non è chiaro se debbano essere contate entrambe.) Questa risposta ritiene che le occorrenze sovrapposte non siano contate come distinte. Naturalmente, poiché la formulazione di OP suggerisce fortemente che guessavrà sempre lunghezza 1, l'ambiguità non sorge.
Ted Hopp

0

Ho avuto anche questo problema, finché non ho escogitato questo metodo.

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

Questo metodo può essere utilizzato per trovare indici di qualsiasi flag di qualsiasi lunghezza in una stringa, ad esempio:

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

Una classe per dividere le corde che mi è venuta. Alla fine viene fornito un breve test.

SplitStringUtils.smartSplitToShorterStrings(String str, int maxLen, int maxParts) sarà diviso per spazi senza spezzare parole, se possibile, e in caso contrario, sarà diviso per indici secondo maxLen.

Altri metodi forniti per controllare come viene suddiviso: 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;
  }
}

Codice di prova semplice:

  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

Questa è una soluzione 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

Questo può essere fatto iterando myStringe spostando il fromIndexparametro in indexOf():

  int currentIndex = 0;

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

    System.out.println(currentIndex);

    currentIndex++;
  }

Hai anche provato a eseguire questo codice? Stamperà ogni posizione (0, 1, 2, ...) fino all'indice dell'ultima occorrenza di mySubstring, indipendentemente dal fatto che mySubstringpossa essere trovato in ciascuna posizione. Niente affatto quello che voleva OP ..
Ted Hopp

-4

Prova questo

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

System.out.println(StringUtils.countMatches(str, findStr));

Questo è utile per contare le istanze di una sottostringa in una stringa più grande, ma non restituisce gli indici delle corrispondenze.
fiveclubs

Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo su come e / o perché risolve il problema migliorerebbe il valore a lungo termine della risposta.
Nic3500

Questo non risponde alla domanda. La domanda richiede un elenco di tutti gli indici
sheu
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.