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

Trufa
fonte

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

Ted Hopp
fonte
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);
}
Peter Lawrey
fonte
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();
POSIX_ME_HARDER
fonte
4

Com o Java9, pode-se fazer uso do iterate(int seed, IntPredicate hasNext,IntUnaryOperator next)seguinte: -

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
fonte
3
int index = -1;
while((index = text.indexOf("on", index + 1)) >= 0) {
   LOG.d("index=" + index);
}
urSus
fonte
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]
Pavneet_Singh
fonte
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
fonte
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);
idris yıldız
fonte
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());
}
Elite Vip
fonte
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);
    }
}
Ian S.
fonte
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();
  }
Dariusz
fonte
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;
    }
Bamidele Alegbe
fonte
-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++;
  }
Zon
fonte
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));
Vikas Kumbhar
fonte
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