Complete a String containing comma and dot separated integers - java

Question:
Given an input String like "1,2,3..6..8,9..11", we have to convert it into "1,2,3,4,5,6,7,8,9,10,11". So basically we have to populate the ranges mentioned by dots. Below is my solution. Is there any better way to solve this ? Can we optimize this further ?
public class FlattenAString {
public static String flattenAString(String input) {
StringBuilder sbr = new StringBuilder("");
StringBuilder current = new StringBuilder("");
StringBuilder next = new StringBuilder("");
int i = 0;
while (i < input.length()) {
if (input.charAt(i) == '.') {
i = i + 2;
while (i != input.length() && input.charAt(i) != '.' && input.charAt(i) != ',') {
next.append(input.charAt(i));
i++;
}
int currentInt = Integer.parseInt(current.toString());
int nextInt = Integer.parseInt(next.toString());
appendFromCurrentTillPrevToNextInt(currentInt, nextInt, sbr);
current = next;
next = new StringBuilder("");
} else if (input.charAt(i) == ',') {
sbr.append(current);
sbr.append(',');
current = new StringBuilder("");
i++;
} else {
current.append(input.charAt(i));
i++;
}
}
sbr.append(current);
return sbr.toString();
}
private static void appendFromCurrentTillPrevToNextInt(int current, int val, StringBuilder sbr) {
for (int i = current; i < val; i++) {
sbr.append(i);
sbr.append(',');
}
}
}

I would approach this by splitting your input string twice. First, split by comma to get either single numbers or ranges with ellipsis. For single numbers, simply add them to a list. For ranges, do a second split on .. to obtain another list of numbers. Then iterate over the range of each of these pairs to fill in the missing values.
Note one tricky point here is that we need to avoid double counting a number position in a range. This is best explained by example:
3..6..8
For this range, we first add 3, 4, 5, 6. But for the second ellipsis, we begin at 7, and then continue until hitting 8.
String input = "1,2,3..6..8,9..11";
String[] parts = input.split(",");
List<Integer> list = new ArrayList<>();
for (String part : parts) {
if (!part.contains("..")) {
list.add(Integer.parseInt(part));
}
else {
String[] ranges = part.split("\\.\\.");
for (int i=0; i < ranges.length-1; ++i) {
int start = Integer.parseInt(ranges[i]) + (i == 0 ? 0 : 1);
int end = Integer.parseInt(ranges[i+1]);
for (int j=start; j <= end; ++j) list.add(j);
}
}
}
// print list of numbers
for (int i=0; i < list.size(); ++i) {
System.out.print((i > 0 ? ", " : "") + list.get(i));
}
Output:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
Demo here:
Rextester

Try this.
static final Pattern RANGE = Pattern.compile("(\\d+)(\\.\\.(\\d+))+");
static String flattenString(String input) {
StringBuffer sb = new StringBuffer();
StringBuilder temp = new StringBuilder();
Matcher m = RANGE.matcher(input);
while (m.find()) {
int begin = Integer.parseInt(m.group(1));
int end = Integer.parseInt(m.group(3));
temp.setLength(0);
for (int i = begin; i <= end; ++i)
temp.append(",").append(i);
m.appendReplacement(sb, temp.substring(1));
}
m.appendTail(sb);
return sb.toString();
}

Related

parsing/converting task with characters and numbers within

It is necessary to repeat the character, as many times as the number behind it.
They are positive integer numbers.
case #1
input: "abc3leson11"
output: "abccclesonnnnnnnnnnn"
I already finish it in the following way:
String a = "abbc2kd3ijkl40ggg2H5uu";
String s = a + "*";
String numS = "";
int cnt = 0;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (Character.isDigit(ch)) {
numS = numS + ch;
cnt++;
} else {
cnt++;
try {
for (int j = 0; j < Integer.parseInt(numS); j++) {
System.out.print(s.charAt(i - cnt));
}
if (i != s.length() - 1 && !Character.isDigit(s.charAt(i + 1))) {
System.out.print(s.charAt(i));
}
} catch (Exception e) {
if (i != s.length() - 1 && !Character.isDigit(s.charAt(i + 1))) {
System.out.print(s.charAt(i));
}
}
cnt = 0;
numS = "";
}
}
But I wonder is there some better solution with less and cleaner code?
Could you take a look below? I'm using a library from StringUtils from Apache Common Utils to repeat character:
public class MicsTest {
public static void main(String[] args) {
String input = "abc3leson11";
String output = input;
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(input);
while (m.find()) {
int number = Integer.valueOf(m.group());
char repeatedChar = input.charAt(m.start()-1);
output = output.replaceFirst(m.group(), StringUtils.repeat(repeatedChar, number));
}
System.out.println(output);
}
}
In case you don't want to use StringUtils. You can use the below custom method to achieve the same effect:
public static String repeat(char c, int times) {
char[] chars = new char[times];
Arrays.fill(chars, c);
return new String(chars);
}
Using java basic string regx should make it more terse as follows:
public class He1 {
private static final Pattern pattern = Pattern.compile("[a-zA-Z]+(\\d+).*");
// match the number between or the last using regx;
public static void main(String... args) {
String s = "abc3leson11";
System.out.println(parse(s));
s = "abbc2kd3ijkl40ggg2H5uu";
System.out.println(parse(s));
}
private static String parse(String s) {
Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
int num = Integer.valueOf(matcher.group(1));
char prev = s.charAt(s.indexOf(String.valueOf(num)) - 1);
// locate the char before the number;
String repeated = new String(new char[num-1]).replace('\0', prev);
// since the prev is not deleted, we have to decrement the repeating number by 1;
s = s.replaceFirst(String.valueOf(num), repeated);
matcher = pattern.matcher(s);
}
return s;
}
}
And the output should be:
abccclesonnnnnnnnnnn
abbcckdddijkllllllllllllllllllllllllllllllllllllllllggggHHHHHuu
String g(String a){
String result = "";
String[] array = a.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
//System.out.println(java.util.Arrays.toString(array));
for(int i=0; i<array.length; i++){
String part = array[i];
result += part;
if(++i == array.length){
break;
}
char charToRepeat = part.charAt(part.length() - 1);
result += repeat(charToRepeat+"", new Integer(array[i]) - 1);
}
return result;
}
// In Java 11 this could be removed and replaced with the builtin `str.repeat(amount)`
String repeat(String str, int amount){
return new String(new char[amount]).replace("\0", str);
}
Try it online.
Explanation:
The split will split the letters and numbers:
abbc2kd3ijkl40ggg2H5uu would become ["abbc", "2", "kd", "3", "ijkl", "40", "ggg", "2", "H", "5", "uu"]
We then loop over the parts and add any strings as is to the result.
We then increase i by 1 first and if we're done (after the "uu") in the array above, it will break the loop.
If not the increase of i will put us at a number. So it will repeat the last character of the part x amount of times, where x is the number we found minus 1.
Here is another solution:
String str = "abbc2kd3ijkl40ggg2H5uu";
String[] part = str.split("(?<=\\d)(?=\\D)|(?=\\d)(?<=\\D)");
String res = "";
for(int i=0; i < part.length; i++){
if(i%2 == 0){
res = res + part[i];
}else {
res = res + StringUtils.repeat(part[i-1].charAt(part[i-1].length()-1),Integer.parseInt(part[i])-1);
}
}
System.out.println(res);
Yet another solution :
public static String getCustomizedString(String input) {
ArrayList<String > letters = new ArrayList<>(Arrays.asList(input.split("(\\d)")));
letters.removeAll(Arrays.asList(""));
ArrayList<String > digits = new ArrayList<>(Arrays.asList(input.split("(\\D)")));
digits.removeAll(Arrays.asList(""));
for(int i=0; i< digits.size(); i++) {
int iteration = Integer.valueOf(digits.get(i));
String letter = letters.get(i);
char c = letter.charAt(letter.length()-1);
for (int j = 0; j<iteration -1 ; j++) {
letters.set(i,letters.get(i).concat(String.valueOf(c)));
}
}
String finalResult = "";
for (String str : letters) {
finalResult += str;
}
return finalResult;
}
The usage:
public static void main(String[] args) {
String testString1 = "abbc2kd3ijkl40ggg2H5uu";
String testString2 = "abc3leson11";
System.out.println(getCustomizedString(testString1));
System.out.println(getCustomizedString(testString2));
}
And the result:
abbcckdddijkllllllllllllllllllllllllllllllllllllllllggggHHHHHuu
abccclesonnnnnnnnnnn

How to split string at every nth occurrence of character in Java

I would like to split a string at every 4th occurrence of a comma ,.
How to do this? Below is an example:
String str = "1,,,,,2,3,,1,,3,,";
Expected output:
array[0]: 1,,,,
array[1]: ,2,3,,
array[2]: 1,,3,,
I tried using Google Guava like this:
Iterable<String> splitdata = Splitter.fixedLength(4).split(str);
output: [1,,,, ,,2,, 3,,1, ,,3,, ,]
I also tried this:
String [] splitdata = str.split("(?<=\\G.{" + 4 + "})");
output: [1,,,, ,,2,, 3,,1, ,,3,, ,]
Yet this is is not the output I want. I just want to split the string at every 4th occurrence of a comma.
Thanks.
Take two int variable. One is to count the no of ','. If ',' occurs then the count will move. And if the count is go to 4 then reset it to 0. The other int value will indicate that from where the string will be cut off. it will start from 0 and after the first string will be detected the the end point (char position in string) will be the first point of the next. Use the this start point and current end point (i+1 because after the occurrence happen the i value will be incremented). Finally add the string in the array list. This is a sample code. Hope this will help you. Sorry for my bad English.
String str = "1,,,,,2,3,,1,,3,,";
int k = 0;
int startPoint = 0;
ArrayList<String> arrayList = new ArrayList<>();
for (int i = 0; i < str.length(); i++)
{
if (str.charAt(i) == ',')
{
k++;
if (k == 4)
{
String ab = str.substring(startPoint, i+1);
System.out.println(ab);
arrayList.add(ab);
startPoint = i+1;
k = 0;
}
}
}
Here's a more flexible function, using an idea from this answer:
static List<String> splitAtNthOccurrence(String input, int n, String delimiter) {
List<String> pieces = new ArrayList<>();
// *? is the reluctant quantifier
String regex = Strings.repeat(".*?" + delimiter, n);
Matcher matcher = Pattern.compile(regex).matcher(input);
int lastEndOfMatch = -1;
while (matcher.find()) {
pieces.add(matcher.group());
lastEndOfMatch = matcher.end();
}
if (lastEndOfMatch != -1) {
pieces.add(input.substring(lastEndOfMatch));
}
return pieces;
}
This is how you call it using your example:
String input = "1,,,,,2,3,,1,,3,,";
List<String> pieces = splitAtNthOccurrence(input, 4, ",");
pieces.forEach(System.out::println);
// Output:
// 1,,,,
// ,2,3,,
// 1,,3,,
I use Strings.repeat from Guava.
try this also, if you want result in array
String str = "1,,,,,2,3,,1,,3,,";
System.out.println(str);
char c[] = str.toCharArray();
int ptnCnt = 0;
for (char d : c) {
if(d==',')
ptnCnt++;
}
String result[] = new String[ptnCnt/4];
int i=-1;
int beginIndex = 0;
int cnt=0,loopcount=0;
for (char ele : c) {
loopcount++;
if(ele==',')
cnt++;
if(cnt==4){
cnt=0;
result[++i]=str.substring(beginIndex,loopcount);
beginIndex=loopcount;
}
}
for (String string : result) {
System.out.println(string);
}
This work pefectly and tested in Java 8
public String[] split(String input,int at){
String[] out = new String[2];
String p = String.format("((?:[^/]*/){%s}[^/]*)/(.*)",at);
Pattern pat = Pattern.compile(p);
Matcher matcher = pat.matcher(input);
if (matcher.matches()) {
out[0] = matcher.group(1);// left
out[1] = matcher.group(2);// right
}
return out;
}
//Ex: D:/folder1/folder2/folder3/file1.txt
//if at = 2, group(1) = D:/folder1/folder2 and group(2) = folder3/file1.txt
The accepted solution above by Saqib Rezwan does not add the leftover string to the list, if it divides the string after every 4th comma and the length of the string is 9 then it will leave the 9th character, and return the wrong list.
A complete solution would be :
private static ArrayList<String> splitStringAtNthOccurrence(String str, int n) {
int k = 0;
int startPoint = 0;
ArrayList<String> list = new ArrayList();
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == ',') {
k++;
if (k == n) {
String ab = str.substring(startPoint, i + 1);
list.add(ab);
startPoint = i + 1;
k = 0;
}
}
// if there is no comma left and there are still some character in the string
// add them to list
else if (!str.substring(i).contains(",")) {
list.add(str.substring(startPoint));
break;
}
}
return list;
}
}

How to break an Integer[] arr in more than one interger[] arrs in Java?

I have a comma separated string of IDs. I want to break this comma separated string in more than one strings if total no. of IDs are greater than 500.
What I can do:
I can convert this string in to integer array and then test it's size. Break than array in more than one arrays, and re-convert them in comma separated strings.
My code so far:
Integer[] empIdInt = null;
String tokens[]=Application.splitstr(outerArray, ",");
if(!ErmUtil.isNull(tokens) && tokens.length>0){
empIdInt=new Integer[tokens.length];
for(int i=0;i<tokens.length;i++){
empIdInt[i]=Integer.valueOf(tokens[i]);
}
}
Questions
is it right approach to tackle this problem?
if yes,how to break integer[] array in more than one arrays?
if no, what should i do?
Edit:
input : "1,2,3,4,5,6,7,8,9,10,11" //list of ids;
I want to break them more than one string if no. of ids is greater than let's say 3. As we it's 10 i.e total no. of ids. so output might be
Output "1,2,3" //1st string
"4,5,6" //2nd string
"7,8,9" //3rd string
"10" //4th string
I have use List<String> to store your data and as per count i have use List.subList(fromIndex,toIndex) method to get subList from main List.
Try below code :
String str = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15";
String[] ar_str = str.split(",");
List<String> list = Arrays.asList(ar_str);
int count = 4;
int fromIndex = 0;
int toIndex = count;
for(int i=0;i<list.size()/count;i++){
fromIndex = i * count;
toIndex = fromIndex + count;
List<String> temp = list.subList(fromIndex, toIndex);
System.out.println(temp); //Convert List into comma separated String
}
if(list.size()%count > 0){
System.out.println(list.subList(toIndex, list.size()));
}
OutPut
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
[13, 14, 15]
May this will help you.
I dont think it is a good option to convert it into integer and then count the integers when you can do the same by counting the "," (commas) in your input string.Use StringUtils class of apache which would make your task easier.Here I have assumed list size as 2,you will have to change it too 500 for your case.Try this :
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class test {
public static void main(String[] args) {
String input = "1,2,3,4,5,6";
List<String> strList=new ArrayList<String>();
while (StringUtils.ordinalIndexOf(input, ",", 2) != -1) {
String s1 = input.substring(0, StringUtils.ordinalIndexOf(input, ",", 2));
String leftover = input.substring(StringUtils.ordinalIndexOf(input, ",", 2) + 1);
input = leftover;
strList.add(s1);
}
if(input!=""){
//for leftover strings which are less than your specified list size
strList.add(input);
}
System.out.println(strList);
}
}
public static List<String> breakStrings(String idListString) {
int limit = 3;
char separator = ',';
String[] idList = idListString.split("\\" + separator);
List<String> finalList = new ArrayList<String>();
if (idList != null && idList.length > 3) {
int j = 0;
int index = 0;
StringBuffer oneList = null;
while (j < idList.length) {
oneList = new StringBuffer();
for (int i = 0; i < limit && index < idList.length; i++) {
boolean isLast = (i + 1) == limit
|| (index + 1) == idList.length;
oneList.append(idList[index++]);
if (!isLast) {
oneList.append(separator);
}
}
finalList.add(oneList.toString());
j += limit;
}
} else {
finalList.add(idListString);
}
return finalList;
}
This will give you list of final strings according to your requirement. Hope this will help you.
Check this
int[] test={10212,10202,11000,11000,11010};
ArrayList<Integer> test2 = new ArrayList<Integer>();
for(int i = test.length -1; i >= 0; i--){
int temp = test[i];
while(temp>0){
test2.add(0, temp%10); //place low order digit in array
temp = temp /10; //remove low order digit from temp;
}
}
To get the count of ID in string and divide it into multiple Integer arrays you can do something like this.
String str = "1234,567,123,4567,890";
String strArray[] = str.split(",");
if (strArray.length > 500) {
Integer[][] ids = new Integer[300][2];
int j = 0;
int i = 0;
for (String s : strArray) {
if (i < 2) {
ids[j][i] = Integer.parseInt(s);
} else {
i = 0;
j = j + 1;
}
}
}
}

how to extract longest sub string (having distinct consecutive character) from a string in java

I want to extract longest distinct consecutive substring from a string
for eg:
1 )abcdeddd
should give
abcde
2) aaabcdrrr
abcd
i wrote this code
for (int i = 0; i < lines; i++) {
String s = bf.readLine();
ArrayList<String> al = new ArrayList<String>();
TreeMap<Integer, Integer> count = new TreeMap<Integer, Integer>();
int point = 0;
for (int j = 0; j < s.length() - 1; j++) {
if (s.charAt(j + 1) != s.charAt(j)) {
Character xyz = s.charAt(j);
String news = al.get(point).concat(xyz.toString());
al.add(point, news);
} else if (s.charAt(j + 1) == s.charAt(j)) {
point++;
}
for (int k = 0; k < al.size(); k++) {
count.put(al.get(k).length(), k);
}
System.out.println(al.get(count.get(count.size() - 1)));
}
}
} catch (Exception e) {
}
}
You can try this way too.
String s = "abcdefgdrrstqrstuvwxyzprr";
Map<Integer,String> results=new HashMap<>();
Set<String> set=new LinkedHashSet<>();
for(int i=0;i<s.length()-1;i++){
if(s.charAt(i)-s.charAt(i+1)==-1){
set.add(""+s.charAt(i));
set.add(""+s.charAt(i+1));
}else {
results.put(set.size(), set.toString());
set=new LinkedHashSet<>();
}
}
System.out.println(results);
Out put:
{0=[], 3=[r, s, t], 7=[a, b, c, d, e, f, g], 10=[q, r, s, t, u, v, w, x, y, z]}
Now you can see all consecutive chars. and answer is largest one. In this way you can find more than one consecutive substring if they are in same length.
You can get it
String largest=new ArrayList<>(results.values())
.get(results.size()-1).replaceAll("\\[|]|, ","");
if("".equals(largest)){
System.out.println("There is not consecutive substring for \""+s+"\"");
}else {
System.out.println("largest consecutive substring of \""+s+"\" is "+ largest);
}
Now out put:
largest consecutive substring of "abcdefgdrrstqrstuvwxyzprr" is qrstuvwxyz
You can iterate/check each of the character starting from character x where x is the starting point of the character checking, then increment to check if the next index of character is corresponds to the next alphabet from the last character.
sample:
String s = "abcdefgdrrstqrstuvwxyzprr";
int start = s.charAt(0);
StringBuilder temp = new StringBuilder();
String temp2 = "";
boolean done = false;
for(int i = 0; i < s.toCharArray().length; i++)
{
if(s.toCharArray()[i] == start) {
temp.append(s.toCharArray()[i]);
start++;
done = true;
if(i == s.toCharArray().length-1)
temp2 = !(temp2.length() > temp.length()) ? temp.toString() : temp2;
}else
{
if(done)
{
if(!(temp2.length() > temp.length()))
temp2 = temp.toString();
--i;
}
temp = new StringBuilder("");
done = false;
start = (i == s.toCharArray().length-1) ? 0 : s.toCharArray()[i+1];
}
}
System.out.println("LONGEST IS: " + temp2);
result:
qrstuvwxyz
And if the test String is abcdeddd the result would be abcde
Here is my solution:
String input = "abcdabcdeabcedeabcdefffff";
String longest = "";
String temp = "";
for(int pos=0; pos<input.length(); pos++) {
if(temp.isEmpty()) {
temp = String.valueOf(input.charAt(pos));
} else if(input.charAt(pos) == temp.charAt(temp.length() - 1) + 1) {
temp += input.charAt(pos);
} else {
temp = String.valueOf(input.charAt(pos));
}
if(temp.length() > longest.length())
longest = temp;
}
System.out.println(longest);
You could also use a StringBuilder for temp as it is more efficient for building Strings in Java.

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]
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.]
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);
}
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]
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();
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);
int index = -1;
while((index = text.indexOf("on", index + 1)) >= 0) {
LOG.d("index=" + index);
}
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();
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);
}
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);
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());
}
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);
}
}
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();
}
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;
}
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++;
}
Try this
String str = "helloslkhellodjladfjhello";
String findStr = "hello";
System.out.println(StringUtils.countMatches(str, findStr));

Categories

Resources