Índices de todas las apariciones de caracteres en una cadena


101

El siguiente código imprimirá 2

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

Me gustaría saber cómo obtener todos los índices de "n" ("adivinar") en la cadena "bannanas"

El resultado esperado sería: [2,3,5]

Respuestas:


162

Esto debería imprimir la lista de posiciones sin el -1al final que ha tenido la solución de Peter Lawrey .

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

También se puede hacer como un forbucle:

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

[Nota: si guesspuede ser más largo que un solo carácter, entonces es posible, al analizar la guesscadena, recorrer wordmás rápido que los bucles anteriores. El punto de referencia para tal enfoque es el algoritmo de Boyer-Moore . Sin embargo, las condiciones que favorecerían el uso de tal enfoque no parecen darse.]


28

Intente lo siguiente (¡que ahora no imprime -1 al final!)

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

1
siempre imprime -1 al final
lukastymo

@Peter Muchas gracias por su respuesta, parece ser correcto, pero este es en realidad mi primer día con Java, así que estoy un poco confundido con el resultado final, esto parece generar -1 al final y no lo hago ' ¡Entiendo muy bien por qué! ¡¡Gracias!!
Trufa

@Trufa: Siempre imprime -1 al final porque indexOfdevuelve -1 cuando no se encuentra el carácter.
ColinD

@Trufa: la razón por la que se imprime -1al final es que el dobucle ejecuta el cuerpo y luego lo descubre index == -1en la terminación while.
Ted Hopp

@ColinD entiendo esa parte, lo que no entiendo es qué sucede con la función para que eso suceda, "recorre" la palabra buscando la ocurrencia del carácter y hasta que no puede encontrar más bien ? e imprime este último índice de que es el no encontrado (-1), ¿es eso lo que está pasando? (No sé si salió bien)
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);
    }
}

El resultado se usaría así:

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

O como una matriz:

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

La idea general es correcta, pero word.substring(word)no se compilará. : P
Peter Lawrey

1
Todavía tiene un problema: imprime continuamente 2.
POSIX_ME_HARDER

Dios, necesito javac todo lo que publico aquí.
pregunta

1

Esto se puede hacer de manera funcional con Java 9 usando expresiones regulares:

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

Aquí está la solución de Kotlin para agregar esta lógica como un nuevo método nuevo en la CharSequenceAPI usando el método de extensión:

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

Además, si desea encontrar todos los índices de una cadena en una cadena.

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

Esto es interesante porque plantea una ambigüedad en el significado de "todas las ocurrencias". Si guess fue "aba"y wordfue "ababa", no está claro si guessocurre una o dos veces en word. (Quiero decir, está claro que uno puede encontrar guesscomenzando en dos posiciones distintas, pero dado que las ocurrencias se superponen, no está claro si ambas deben contarse). Esta respuesta considera que las ocurrencias superpuestas no se cuentan como distintas. Por supuesto, dado que la redacción de OP sugiere fuertemente que guesssiempre tendrá la longitud 1, la ambigüedad no surge.
Ted Hopp

0

También tuve este problema, hasta que se me ocurrió este método.

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

Este método se puede utilizar para encontrar índices de cualquier bandera de cualquier longitud en una cadena, por ejemplo:

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

Se me ocurrió una clase para partir cuerdas. Se proporciona una breve prueba al final.

SplitStringUtils.smartSplitToShorterStrings(String str, int maxLen, int maxParts) se dividirá por espacios sin romper palabras, si es posible, y si no, se dividirá por índices de acuerdo con maxLen.

Otros métodos proporcionados para controlar cómo se divide: 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;
  }
}

Código de prueba simple:

  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

Esta es una solución de 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

Esto se puede hacer iterando myStringy cambiando el fromIndexparámetro en indexOf():

  int currentIndex = 0;

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

    System.out.println(currentIndex);

    currentIndex++;
  }

¿Intentaste ejecutar este código? Imprimirá todas las posiciones (0, 1, 2, ...) hasta el índice de la última aparición de mySubstring, independientemente de si mySubstringse pueden encontrar en cada posición. No es en absoluto lo que quería OP ..
Ted Hopp

-4

Prueba esto

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

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

Esto es bueno para contar instancias de una subcadena en una cadena más grande, pero no devuelve los índices de las coincidencias.
fiveclubs

Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre cómo y / o por qué resuelve el problema mejoraría el valor de la respuesta a largo plazo.
Nic3500

Esto no responde a la pregunta. La pregunta requiere una lista de todos los índices
sheu
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.