Вопрос-ответ

How do I count the number of occurrences of a char in a String?

Как мне подсчитать количество вхождений символа char в строку?

У меня есть строка

a.b.c.d

Я хочу подсчитать вхождения '.' идиоматическим способом, предпочтительно однострочным.

(Ранее я выражал это ограничение как "без цикла", на случай, если вам интересно, почему все пытаются ответить без использования цикла).

Переведено автоматически
Ответ 1

Как насчет этого. Он не использует регулярное выражение внизу, поэтому должен быть быстрее, чем некоторые другие решения, и не будет использовать цикл.

int count = line.length() - line.replace(".", "").length();
Ответ 2

Мой "идиоматический однострочник" для этого:

int count = StringUtils.countMatches("a.b.c.d", ".");

Зачем писать это самостоятельно, если это уже есть на commons lang?

Единственным параметром Spring Framework для этого является:

int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");
Ответ 3

Обобщите другой ответ и то, что я знаю обо всех способах сделать это, используя однострочный:

   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, для a.b.c.d это сработает, но для a .b.c...d или ...a.b.c.d или a....b.....c....d ... или etc. это не сработает. Это просто будет учитываться . между символами только один раз

Подробнее на github

Тест производительности (используя JMH, mode = среднее время, оценка 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
Ответ 4

Рано или поздно, что-то должно зацикливаться. Вам гораздо проще написать (очень простой) цикл, чем использовать что-то вроде 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;
}

Тогда вам не нужно иметь цикл в вашем основном коде - но цикл должен быть где-то там.

java string