Reputation: 209
I'm trying to count the number of symbol (String) occurrences within a text (String). I've seen some other solutions here, but they're more advanced or use libraries. My idea is to reduce the string at each occurrence of the symbol. I use .indexOf(symbol,1)
to search for symbol from index 1 because if it searches at 0 it just stops. However, the code overcounts by one most of the time.
String text = readLine("Enter text");
String symbol = readLine("Enter symbol");
int count = 0;
while (true) {
if (!text.contains(symbol)) {
break;
}
count++;
if ((text.indexOf(symbol, 1)) == -1) {
break;
}
text = text.substring(text.indexOf(symbol, 1));
System.out.println(text);
System.out.println(count);
}
System.out.println("Symbol " + symbol + " appears in text " + count + " times.");
Please help me find the flaw in logic, and also tell me if this approach is good or bad.
Upvotes: 0
Views: 2551
Reputation: 89527
An alternative to using substring
is to keep track of the previous index the string was found at and use String#indexOf(str, fromIndex)
.
int count = 0;
for(int idx = -1; (idx = text.indexOf(symbol, idx + 1)) != -1; count++);
System.out.println("Symbol " + symbol + " appears in text " + count + " times.");
Upvotes: 0
Reputation: 70584
Since tibetiroka has already identified the flaw in your code, I'll only tackle the second part of your question:
also tell me if this approach is good or bad.
It works, but it is both quite complicated and not very efficient at runtime. The reason is that substring()
copies all remaining characters into a new string. For instance, suppose your text contains the symbol 1000 times, and nothing else. Then, after finding the first symbol, your code will copy the 999 remaining symbols, and 998 after finding the second symbol, and so on, for a total of about 500 000 symbol copies, even though there are only 1000 symbols in the text!
It is therefore better to avoid substring()
, and instead use the second parameter to indexOf()
to resume looking after the last symbol found:
int count = 0;
int index = 0;
while (true) {
index = text.indexOf(symbol, index); // find next occurrence of symbol
if (index == -1) {
return count;
}
count++;
index++;
}
I've also eliminated the use of contains()
, since indexOf()
already tells us if there is another occurrence.
One last thing: You didn't specify whether overlapping symbols should be counted. For instance, if we look for "aba" in the text "ababa", is that one or two occurrences? If occurrences shouldn't overlap, we can achieve this by saying index += symbol.length
whenever we find a symbol.
Upvotes: 1
Reputation: 357
I think you can try the following:
String text = readLine("Enter text");
char symbol = readLine("Enter symbol").charAt(0);
int count = 0;
for(char character: text.toCharArray()) {
if(symbol == character) {
count++;
}
}
System.out.println("Count: " + count);
This just loops through each character of the string and compares it to the entered symbol
Upvotes: 0
Reputation:
if (!text.contains(symbol)) {
break;
}
count++;
if ((text.indexOf(symbol, 1)) == -1) {
break;
}
This part of your code is quite problematic. You increment the count if the symbol is present in the text, even if it is the first character - while your
text = text.substring(text.indexOf(symbol, 1));
code assures that the first character is the specified symbol in the text. This causes your code to overcount by one if it contains the specified symbol. To fix it, change your code to
while (true) {
if (!text.contains(symbol)) {
break;
}
count++;
text = text.substring(text.indexOf(symbol)+1);//+1 so it starts at the next character
System.out.println(text);
System.out.println(count);
}
As you can see, the first character is no longer the specified symbol. This ensures that
contains()
method is enough to determine the presence of the symbolcount
is set correctlyUpvotes: 1