Trufa
Trufa

Reputation: 40747

Indexes of all occurrences of character in a string

The following code will print 2

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

I would like to know how to get all the indexes of "n" ("guess") in the string "bannanas"

The expected result would be: [2,3,5]

Upvotes: 133

Views: 246060

Answers (16)

4shutosh
4shutosh

Reputation: 56

Based on @Pavneet_Singh's answer, a kotlin extension function to return a pair of start and end of the substring, and ignore cases.

fun CharSequence.indicesOf(input: String): List<Pair<Int, Int>> =
Pattern.compile(input, Pattern.CASE_INSENSITIVE).toRegex()
    .findAll(this)
    .map { Pair(it.range.first, it.range.last) }
    .toCollection(mutableListOf())

Upvotes: 0

Unmitigated
Unmitigated

Reputation: 89527

Java 8+

To find all the indexes of a particular character in a String, one can create an IntStream of all the indexes and filter over it.

import java.util.stream.Collectors;
import java.util.stream.IntStream;
//...
String word = "bannanas";
char search = 'n';
//To get List of indexes:
List<Integer> indexes = IntStream.range(0, word.length())
        .filter(i -> word.charAt(i) == search).boxed()
        .collect(Collectors.toList());
//To get array of indexes:
int[] indexes = IntStream.range(0, word.length())
        .filter(i -> word.charAt(i) == search).toArray();

Upvotes: 5

Pavneet_Singh
Pavneet_Singh

Reputation: 37414

This can be done in a functional way with Java 9 using regular expression:

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

Here's the Kotlin Solution to add this logic as a new a new methods into CharSequence API using extension method:

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

Upvotes: 15

Bamidele Alegbe
Bamidele Alegbe

Reputation: 534

This is a java 8 solution.

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

Upvotes: 2

Vikas Kumbhar
Vikas Kumbhar

Reputation: 121

Try this

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

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

Upvotes: -5

Naman
Naman

Reputation: 32046

With Java9, one can make use of the iterate(int seed, IntPredicate hasNext,IntUnaryOperator next) as follows:-

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

Upvotes: 7

Ted Hopp
Ted Hopp

Reputation: 234857

This should print the list of positions without the -1 at the end that Peter Lawrey's solution has had.

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

It can also be done as a for loop:

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

[Note: if guess can be longer than a single character, then it is possible, by analyzing the guess string, to loop through word faster than the above loops do. The benchmark for such an approach is the Boyer-Moore algorithm. However, the conditions that would favor using such an approach do not seem to be present.]

Upvotes: 202

Dariusz
Dariusz

Reputation: 22311

A class for splitting strings I came up with. A short test is provided at the end.

SplitStringUtils.smartSplitToShorterStrings(String str, int maxLen, int maxParts) will split by spaces without breaking words, if possible, and if not, will split by indexes according to maxLen.

Other methods provided to control how it is split: 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;
  }
}

Simple test code:

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

Upvotes: 1

Ian S.
Ian S.

Reputation: 1971

I had this problem as well, until I came up with this method.

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

This method can be used to find indexes of any flag of any length in a string, for example:

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

Upvotes: 1

Zon
Zon

Reputation: 19918

This can be done by iterating myString and shifting fromIndex parameter in indexOf():

  int currentIndex = 0;

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

    System.out.println(currentIndex);

    currentIndex++;
  }

Upvotes: 1

Elite Vip
Elite Vip

Reputation: 11

Also, if u want to find all indexes of a String in a String.

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

Upvotes: 1

urSus
urSus

Reputation: 12759

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

Upvotes: 5

idris yıldız
idris yıldız

Reputation: 2117

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

Upvotes: 1

Peter Lawrey
Peter Lawrey

Reputation: 533890

Try the following (Which does not print -1 at the end now!)

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

Upvotes: 33

asgs
asgs

Reputation: 3984

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

Upvotes: 3

POSIX_ME_HARDER
POSIX_ME_HARDER

Reputation: 762

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

Result would be used like this :

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

Or as a array :

list.toArray();

Upvotes: 9

Related Questions