У меня есть строка
a.b.c.d
Я хочу подсчитать вхождения '.' идиоматическим способом, предпочтительно однострочным.
(Раньше я выражал это ограничение как "без цикла", если вам интересно, почему все пытаются ответить, не используя цикл).
У меня есть строка
a.b.c.d
Я хочу подсчитать вхождения '.' идиоматическим способом, предпочтительно однострочным.
(Раньше я выражал это ограничение как "без цикла", если вам интересно, почему все пытаются ответить, не используя цикл).
Мой "идиоматический однострочный" для этого:
int count = StringUtils.countMatches("a.b.c.d", ".");
Зачем писать его самостоятельно, когда он уже находится в commons lang?
Spring Framework oneliner для этого:
int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");
Как насчет этого. Он не использует regexp внизу, поэтому должен быть быстрее, чем некоторые другие решения, и не будет использовать цикл.
int count = line.length() - line.replace(".", "").length();
Подведите итог другому ответу, и я знаю все способы сделать это с помощью однострочного интерфейса:
String testString = "a.b.c.d";
1) Использование Apache Commons
int apache = StringUtils.countMatches(testString, ".");
System.out.println("apache = " + apache);
2) Используя Spring Framework
int spring = org.springframework.util.StringUtils.countOccurrencesOf(testString, ".");
System.out.println("spring = " + spring);
3) Используя заменить
int replace = testString.length() - testString.replace(".", "").length();
System.out.println("replace = " + replace);
4) Используя replaceAll (случай 1)
int replaceAll = testString.replaceAll("[^.]", "").length();
System.out.println("replaceAll = " + replaceAll);
5) Используя replaceAll (случай 2)
int replaceAllCase2 = testString.length() - testString.replaceAll("\\.", "").length();
System.out.println("replaceAll (second case) = " + replaceAllCase2);
6) Используя split
int split = testString.split("\\.",-1).length-1;
System.out.println("split = " + split);
7) Использование Java8 (случай 1)
long java8 = testString.chars().filter(ch -> ch =='.').count();
System.out.println("java8 = " + java8);
8) Использование Java8 (случай 2) может быть лучше для unicode, чем случай 1
long java8Case2 = testString.codePoints().filter(ch -> ch =='.').count();
System.out.println("java8 (second case) = " + java8Case2);
9) Использование StringTokenizer
int stringTokenizer = new StringTokenizer(" " +testString + " ", ".").countTokens()-1;
System.out.println("stringTokenizer = " + stringTokenizer);
Из комментария: будьте внимательны к StringTokenizer, для abcd он будет работать, но для... bc... d или... abcd или a... b...... c..... d... или т.д. это не сработает. Он просто рассчитывает. между символами только один раз
Дополнительная информация в github
Perfomance test (используя JMH, mode = AverageTime, оценка 0.010
лучше, чем 0.351
):
Benchmark Mode Cnt Score Error Units
1. countMatches avgt 5 0.010 ± 0.001 us/op
2. countOccurrencesOf avgt 5 0.010 ± 0.001 us/op
3. stringTokenizer avgt 5 0.028 ± 0.002 us/op
4. java8_1 avgt 5 0.077 ± 0.005 us/op
5. java8_2 avgt 5 0.078 ± 0.003 us/op
6. split avgt 5 0.137 ± 0.009 us/op
7. replaceAll_2 avgt 5 0.302 ± 0.047 us/op
8. replace avgt 5 0.303 ± 0.034 us/op
9. replaceAll_1 avgt 5 0.351 ± 0.045 us/op
Рано или поздно что-то должно зацикливаться. Для вас гораздо проще написать (очень простой) цикл, чем использовать что-то вроде split
, которое намного мощнее, чем вам нужно.
Во всех случаях инкапсулировать цикл в отдельный метод, например
public static int countOccurrences(String haystack, char needle)
{
int count = 0;
for (int i=0; i < haystack.length(); i++)
{
if (haystack.charAt(i) == needle)
{
count++;
}
}
return count;
}
Тогда вам не нужно иметь цикл в вашем основном коде, но цикл должен быть где-то там.
У меня была идея, похожая на Младена, но наоборот...
String s = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();
ReplaceAll ( "." ) заменит все символы.
Решение PhiLho использует ReplaceAll ( "[^.]", "" ), который не нужно экранировать, поскольку [.] представляет символ "точка" ', а не "любой символ".
Мое решение 'iiomatic one-liner':
int count = "a.b.c.d".length() - "a.b.c.d".replace(".", "").length();
Не знаю, почему принимается решение, использующее StringUtils.
String s = "a.b.c.d";
long result = s.chars().filter(ch -> ch == '.').count();
Более короткий пример
String text = "a.b.c.d";
int count = text.split("\\.",-1).length-1;
здесь есть решение без цикла:
public static int countOccurrences(String haystack, char needle, int i){
return ((i=haystack.indexOf(needle, i)) == -1)?0:1+countOccurrences(haystack, needle, i+1);}
System.out.println("num of dots is "+countOccurrences("a.b.c.d",'.',0));
ну, есть цикл, но он невидим: -)
- Йонатан
Мне не нравится идея выделения новой строки для этой цели. И поскольку в строке уже есть массив char, где он хранит это значение, String.charAt() практически свободен.
for(int i=0;i<s.length();num+=(s.charAt(i++)==delim?1:0))
делает трюк без дополнительных ассигнований, которые нуждаются в коллекции, в 1 строке или меньше, только с J2SE.
Хорошо, вдохновленный решением Yonatan, здесь, который является чисто рекурсивным - единственными используемыми библиотечными методами являются length()
и charAt()
, ни один из которых не выполняет цикл:
public static int countOccurrences(String haystack, char needle)
{
return countOccurrences(haystack, needle, 0);
}
private static int countOccurrences(String haystack, char needle, int index)
{
if (index >= haystack.length())
{
return 0;
}
int contribution = haystack.charAt(index) == needle ? 1 : 0;
return contribution + countOccurrences(haystack, needle, index+1);
}
Определяется ли рекурсия как цикл, зависит от того, какое точное определение вы используете, но оно, вероятно, как можно ближе.
Я не знаю, решают ли большинство JVM хвостовую рекурсию в эти дни... если нет, вы, конечно, получите переполнение одноименного стека для подходящих длинных строк.
Вдохновленный Джон Скит, не-петлевая версия, которая не ударит ваш стек. Также полезной отправной точкой, если вы хотите использовать инфраструктуру fork-join.
public static int countOccurrences(CharSequeunce haystack, char needle) {
return countOccurrences(haystack, needle, 0, haystack.length);
}
// Alternatively String.substring/subsequence use to be relatively efficient
// on most Java library implementations, but isn't any more [2013].
private static int countOccurrences(
CharSequence haystack, char needle, int start, int end
) {
if (start == end) {
return 0;
} else if (start+1 == end) {
return haystack.charAt(start) == needle ? 1 : 0;
} else {
int mid = (end+start)>>>1; // Watch for integer overflow...
return
countOccurrences(haystack, needle, start, mid) +
countOccurrences(haystack, needle, mid, end);
}
}
(Отказ от ответственности: не проверен, не скомпилирован, не разумен.)
Возможно, лучший (однопоточный, без поддержки суррогатной пары) способ записать его:
public static int countOccurrences(String haystack, char needle) {
int count = 0;
for (char c : haystack.toCharArray()) {
if (c == needle) {
++count;
}
}
return count;
}
Не уверен в эффективности этого, но это самый короткий код, который я мог бы написать без привлечения сторонних библиотек:
public static int numberOf(String target, String content)
{
return (content.split(target).length - 1);
}
С java-8 вы также можете использовать потоки для достижения этого. Очевидно, есть итерация за кулисами, но вам не нужно ее явно писать!
public static long countOccurences(String s, char c){
return s.chars().filter(ch -> ch == c).count();
}
countOccurences("a.b.c.d", '.'); //3
countOccurences("hello world", 'l'); //3
Также можно использовать сокращение в Java 8 для решения этой проблемы:
int res = "abdsd3$asda$asasdd$sadas".chars().reduce(0, (a, c) -> a + (c == '$' ? 1 : 0));
System.out.println(res);
Вывод:
3
Полный образец:
public class CharacterCounter
{
public static int countOccurrences(String find, String string)
{
int count = 0;
int indexOf = 0;
while (indexOf > -1)
{
indexOf = string.indexOf(find, indexOf + 1);
if (indexOf > -1)
count++;
}
return count;
}
}
Вызов:
int occurrences = CharacterCounter.countOccurrences("l", "Hello World.");
System.out.println(occurrences); // 3
Самый простой способ получить ответ заключается в следующем:
public static void main(String[] args) {
String string = "a.b.c.d";
String []splitArray = string.split("\\.",-1);
System.out.println("No of . chars is : " + (splitArray.length-1));
}
Если вы используете фреймворк Spring, вы также можете использовать класс "StringUtils". Этот метод будет "countOccurrencesOf".
Вы можете использовать функцию split()
в одной строке кода
int noOccurence=string.split("#",-1).length-1;
public static int countOccurrences(String container, String content){
int lastIndex, currIndex = 0, occurrences = 0;
while(true) {
lastIndex = container.indexOf(content, currIndex);
if(lastIndex == -1) {
break;
}
currIndex = lastIndex + content.length();
occurrences++;
}
return occurrences;
}
import java.util.Scanner;
class apples {
public static void main(String args[]) {
Scanner bucky = new Scanner(System.in);
String hello = bucky.nextLine();
int charCount = hello.length() - hello.replaceAll("e", "").length();
System.out.println(charCount);
}
}// COUNTS NUMBER OF "e" CHAR´s within any string input
В то время как методы могут скрыть это, нет возможности считать без цикла (или рекурсии). Однако вы хотите использовать char [] для повышения производительности.
public static int count( final String s, final char c ) {
final char[] chars = s.toCharArray();
int count = 0;
for(int i=0; i<chars.length; i++) {
if (chars[i] == c) {
count++;
}
}
return count;
}
Использование replaceAll (то есть RE) не похоже на лучший способ.
Где-то в коде что-то должно зацикливаться. Единственный путь вокруг этого - полное разворачивание цикла:
int numDots = 0;
if (s.charAt(0) == '.') {
numDots++;
}
if (s.charAt(1) == '.') {
numDots++;
}
if (s.charAt(2) == '.') {
numDots++;
}
... и т.д., но тогда вы делаете цикл вручную в исходном редакторе, а не на компьютере, который его запустит. См. Псевдокод:
create a project
position = 0
while (not end of string) {
write check for character at position "position" (see above)
}
write code to output variable "numDots"
compile program
hand in homework
do not think of the loop that your "if"s may have been optimized and compiled to
Вот немного другое решение для рекурсии стиля:
public static int countOccurrences(String haystack, char needle)
{
return countOccurrences(haystack, needle, 0);
}
private static int countOccurrences(String haystack, char needle, int accumulator)
{
if (haystack.length() == 0) return accumulator;
return countOccurrences(haystack.substring(1), needle, haystack.charAt(0) == needle ? accumulator + 1 : accumulator);
}
Почему бы просто не разбить на символ, а затем получить длину результирующего массива. длина массива всегда будет числом экземпляров + 1. Правильно?
Следующий исходный код даст вам no.of вхождения данной строки в слово, введенное пользователем: -
import java.util.Scanner;
public class CountingOccurences {
public static void main(String[] args) {
Scanner inp= new Scanner(System.in);
String str;
char ch;
int count=0;
System.out.println("Enter the string:");
str=inp.nextLine();
while(str.length()>0)
{
ch=str.charAt(0);
int i=0;
while(str.charAt(i)==ch)
{
count =count+i;
i++;
}
str.substring(count);
System.out.println(ch);
System.out.println(count);
}
}
}
int count = (line.length() - line.replace("str", "").length())/"str".length();
Ну, с такой же задачей я наткнулся на эту тему. Я не видел ограничений языка программирования, так как groovy работает на java vm: Вот как я смог решить мою проблему с помощью Groovy.
"a.b.c.".count(".")
сделанный.
Использование Коллекции Eclipse
int count = CharAdapter.adapt("a.b.c.d").count(c -> c == '.');
Если у вас есть более одного символа для подсчета, вы можете использовать CharBag
следующим образом:
CharBag bag = CharAdapter.adapt("a.b.c.d").toBag();
int count = bag.occurrencesOf('.');
Примечание. Я являюсь коммиттером для коллекций Eclipse.