Как подсчитать количество появлений символа в строке? - PullRequest
494 голосов
/ 09 ноября 2008

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

a.b.c.d

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

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

Ответы [ 41 ]

959 голосов
/ 18 января 2012

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

int count = line.length() - line.replace(".", "").length();
679 голосов
/ 30 ноября 2009

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

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

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

Springel Framework для этого:

int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");
246 голосов
/ 06 февраля 2016

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

   String testString = "a.b.c.d";

1) Использование Apache Commons

int apache = StringUtils.countMatches(testString, ".");
System.out.println("apache = " + apache);

2) Использование Spring Framework's

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 (case 1)

int replaceAll = testString.replaceAll("[^.]", "").length();
System.out.println("replaceAll = " + replaceAll);

5) Использование replaceAll (case 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) может быть лучше для юникода, чем случай 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

Тест производительности (с использованием 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
170 голосов
/ 09 ноября 2008

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

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

61 голосов
/ 09 ноября 2008

У меня была идея, похожая на Младена, но противоположная ...

String s = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);
35 голосов
/ 09 ноября 2008
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();

ReplaceAll (".") Заменит все символы.

Решение PhiLho использует ReplaceAll ("[^.]", ""), Который не нужно экранировать, поскольку [.] Представляет символ «точка», а не «любой символ».

27 голосов
/ 13 ноября 2013

Моё «идиоматическое однострочное» решение:

int count = "a.b.c.d".length() - "a.b.c.d".replace(".", "").length();

Понятия не имею, почему принято решение, использующее StringUtils.

26 голосов
/ 11 октября 2013
String s = "a.b.c.d";
long result = s.chars().filter(ch -> ch == '.').count();
22 голосов
/ 29 ноября 2009

Более короткий пример -

String text = "a.b.c.d";
int count = text.split("\\.",-1).length-1;
17 голосов
/ 09 ноября 2008

вот решение без цикла:

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

ну, есть цикл, но он невидим : -)

- Йонатан

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...