Indizes aller Vorkommen von Zeichen in einer Zeichenfolge


101

Der folgende Code gibt 2 aus

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

Ich würde gerne wissen, wie man alle Indizes von "n" ("rate") in der Zeichenfolge "bannanas" erhält.

Das erwartete Ergebnis wäre: [2,3,5]

Antworten:


161

Dies sollte die Liste der Positionen , ohne dass der Druck -1am Ende , dass Peter Lawrey-Lösung hat sich hatte.

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

Es kann auch als forSchleife ausgeführt werden:

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

[Hinweis: Wenn guesses länger als ein einzelnes Zeichen sein kann, ist es durch Analysieren der guessZeichenfolge möglich, wordschneller als die obigen Schleifen zu durchlaufen . Der Maßstab für einen solchen Ansatz ist der Boyer-Moore-Algorithmus . Die Bedingungen, die einen solchen Ansatz begünstigen würden, scheinen jedoch nicht gegeben zu sein.]


28

Versuchen Sie Folgendes (das jetzt am Ende nicht -1 druckt!)

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

1
Sie drucken immer -1 am Ende
lukastymo

@Peter Vielen Dank für Ihre Antwort, es scheint richtig zu sein, aber dies ist tatsächlich mein erster Tag mit Java, daher bin ich ein wenig verwirrt über das Endergebnis. Dies scheint am Ende -1 auszugeben und ich nicht. Ich verstehe nicht ganz warum! Vielen Dank!!
Trufa

@Trufa: Es wird immer -1 am Ende ausgegeben, da indexOf-1 zurückgegeben wird, wenn das Zeichen nicht gefunden wird.
ColinD

@Trufa - der Grund , es druckt -1am Ende ist , dass die doSchleife , um den Körper ausführt und dann feststellt, dass index == -1in dem Abschluß while.
Ted Hopp

@ColinD der Teil, den ich bekomme, was ich nicht verstehe, ist, was mit der Funktion passiert, damit das passiert, es "durchläuft" das Wort und sucht nach dem Auftreten des Charakters und bis dahin kann es nicht mehr richtig finden ? und druckt diesen letzten Index davon ist der nicht gefundene (-1), ist das was passiert? (Ich weiß nicht, ob das richtig herauskam)
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);
    }
}

Das Ergebnis würde folgendermaßen verwendet:

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

Oder als Array:

list.toArray();


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

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

Die allgemeine Idee ist richtig, wird aber word.substring(word)nicht kompiliert. : P
Peter Lawrey

1
Immer noch ein Problem: Es wird kontinuierlich
gedruckt

Meine Güte, ich muss alles, was ich hier poste, javac.
Asgs

1

Dies kann mit Java 9 auf funktionale Weise unter Verwendung eines regulären Ausdrucks erfolgen:

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

Hier ist die Kotlin-Lösung, um diese Logik als neue neue Methode in die CharSequenceAPI mithilfe der Erweiterungsmethode einzufügen:

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

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

Auch wenn Sie alle Indizes eines Strings in einem String finden möchten.

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

Dies ist insofern interessant, als es eine Mehrdeutigkeit im Sinne von "allen Vorkommen" aufwirft. Wenn guess war "aba"und wordwar "ababa", ist es nicht klar, ob das guessein- oder zweimal in auftritt word. (Ich meine, es ist klar, dass man guessab zwei verschiedenen Positionen beginnen kann, aber da sich die Vorkommen überlappen, ist nicht klar, ob beide gezählt werden sollten.) Diese Antwort vertritt die Ansicht, dass überlappende Vorkommen nicht als verschieden gezählt werden. Da der Wortlaut von OP stark darauf hindeutet, dass guessimmer die Länge 1 sein wird, tritt die Mehrdeutigkeit natürlich nicht auf.
Ted Hopp

0

Ich hatte auch dieses Problem, bis ich auf diese Methode kam.

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

Diese Methode kann verwendet werden, um Indizes eines beliebigen Flags beliebiger Länge in einer Zeichenfolge zu finden, zum Beispiel:

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

Eine Klasse zum Teilen von Saiten, die ich mir ausgedacht habe. Am Ende wird ein kurzer Test bereitgestellt.

SplitStringUtils.smartSplitToShorterStrings(String str, int maxLen, int maxParts) wird nach Möglichkeit durch Leerzeichen geteilt, ohne Wörter zu brechen, und wenn nicht, wird durch Indizes gemäß maxLen geteilt.

Andere Methoden zur Steuerung der Aufteilung: 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;
  }
}

Einfacher Testcode:

  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

Dies ist eine Java 8-Lösung.

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

Dies kann durch Iterieren myStringund Verschieben von fromIndexParametern in indexOf():

  int currentIndex = 0;

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

    System.out.println(currentIndex);

    currentIndex++;
  }

Haben Sie sogar versucht, diesen Code auszuführen? Es wird jede Position (0, 1, 2, ...) bis zum Index des letzten Auftretens von mySubstringausgedruckt, unabhängig davon, ob mySubstringan jeder Position gefunden werden kann. Überhaupt nicht das, was OP wollte ..
Ted Hopp

-4

Versuche dies

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

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

Dies ist gut zum Zählen von Instanzen eines Teilstrings in einer größeren Zeichenfolge, gibt jedoch nicht die Indizes der Übereinstimmungen zurück.
Fiveclubs

Während dieser Code die Frage beantworten kann, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und / oder warum er das Problem löst, den langfristigen Wert der Antwort verbessern.
Nic3500

Dies beantwortet die Frage nicht. Die Frage erfordert eine Liste aller Indizes
Sheu
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.