Índices de todas as ocorrências de caracteres em uma string


101

O código a seguir imprimirá 2

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

Gostaria de saber como obter todos os índices de "n" ("palpite") na string "bannanas"

O resultado esperado seria: [2,3,5]

Respostas:


162

Isso deve imprimir a lista de posições sem a -1no final que a solução de Peter Lawrey tem tido.

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

Também pode ser feito em forloop:

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

[Nota: se guesspode ser mais longo do que um único caractere, então é possível, analisando a guessstring, fazer um loop wordmais rápido do que os loops acima. O benchmark para tal abordagem é o algoritmo Boyer-Moore . No entanto, as condições que favorecem o uso de tal abordagem não parecem estar presentes.]


28

Tente o seguinte (que não imprime -1 no final agora!)

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

1
você sempre imprime -1 no final
lukastymo

@Peter Muito obrigado por sua resposta, parece estar certo, mas este é na verdade meu primeiro dia com Java, então estou um pouco confuso com o resultado final, parece que a saída -1 no final e não não entendo muito bem por quê! obrigado!!
Trufa

@Trufa: sempre imprime -1 no final porque indexOfretorna -1 quando o caractere não é encontrado.
ColinD

@Trufa - a razão pela qual ele imprime -1no final é que o doloop executa o corpo e, em seguida, descobre isso index == -1na finalização while.
Ted Hopp

@ColinD essa parte eu entendi, o que eu não entendo é o que acontece com a função para que isso aconteça, ela "faz um loop" pela palavra procurando a ocorrência do caractere e até lá não consegue achar mais nada certo ? e imprime esse último índice de que é o não encontrado (-1), é isso que está acontecendo? (Não sei se saiu certo)
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);
    }
}

O resultado seria usado assim:

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

Ou como uma matriz:

list.toArray();


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

2

Isso pode ser feito de maneira funcional com Java 9, usando expressão regular:

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

Esta é a solução Kotlin para adicionar essa lógica como um novo método à CharSequenceAPI usando o método de extensão:

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

A ideia geral está certa, mas word.substring(word)não compila. : P
Peter Lawrey

1
Ainda tem um problema: imprime continuamente 2.
POSIX_ME_HARDER

Puxa, preciso javac de tudo o que posto aqui.
asgs de

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

Além disso, se você quiser encontrar todos os índices de uma String em uma String.

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

Isso é interessante porque levanta uma ambigüidade no significado de "todas as ocorrências". Se guess foi "aba"e wordfoi "ababa", não está claro se guessocorre uma ou duas vezes em word. (Quer dizer, é claro que pode-se encontrar guesscomeçando em duas posições distintas, mas como as ocorrências se sobrepõem, não está claro se ambas devem ser contadas.) Essa resposta considera que ocorrências sobrepostas não são contadas como distintas. Claro, uma vez que o texto de OP sugere fortemente que guesssempre terá comprimento 1, a ambigüidade não surge.
Ted Hopp

0

Eu também tive esse problema, até que inventei esse 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 pode ser usado para encontrar índices de qualquer sinalizador de qualquer comprimento em uma string, por exemplo:

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

Uma classe para dividir cordas que eu criei. Um breve teste é fornecido no final.

SplitStringUtils.smartSplitToShorterStrings(String str, int maxLen, int maxParts) será dividido por espaços sem quebrar palavras, se possível, e se não, será dividido por índices de acordo com maxLen.

Outros métodos fornecidos para controlar como é dividido: 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 teste simples:

  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 é uma solução 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

Isso pode ser feito iterando myStringe mudando o fromIndexparâmetro em indexOf():

  int currentIndex = 0;

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

    System.out.println(currentIndex);

    currentIndex++;
  }

Você ao menos tentou executar este código? Irá imprimir todas as posições (0, 1, 2, ...) até o índice da última ocorrência de mySubstring, independentemente de mySubstringpoder ser encontrado em cada posição. Nem um pouco o que a OP queria ..
Ted Hopp

-4

Tente isto

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

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

Isso é bom para contar instâncias de uma substring em uma string maior, mas não retorna os índices das correspondências.
fiveclubs de

Embora este código possa responder à pergunta, fornecer contexto adicional sobre como e / ou por que ele resolve o problema melhoraria o valor da resposta a longo prazo.
Nic3500

Isso não responde à pergunta. A questão requer uma lista de todos os índices
sheu
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.