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

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

a.b.c.d

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

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

Ответ 1

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

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

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

Spring Framework oneliner для этого:

int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");

Ответ 2

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

int count = line.length() - line.replace(".", "").length();

Ответ 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, для 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

Ответ 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;
}

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

Ответ 5

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

String s = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);

Ответ 6

String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();

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

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

Ответ 7

Мое решение 'iiomatic one-liner':

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

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

Ответ 8

String s = "a.b.c.d";
long result = s.chars().filter(ch -> ch == '.').count();

Ответ 9

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

String text = "a.b.c.d";
int count = text.split("\\.",-1).length-1;

Ответ 10

здесь есть решение без цикла:

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

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

- Йонатан

Ответ 11

Мне не нравится идея выделения новой строки для этой цели. И поскольку в строке уже есть массив char, где он хранит это значение, String.charAt() практически свободен.

for(int i=0;i<s.length();num+=(s.charAt(i++)==delim?1:0))

делает трюк без дополнительных ассигнований, которые нуждаются в коллекции, в 1 строке или меньше, только с J2SE.

Ответ 12

Хорошо, вдохновленный решением 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 хвостовую рекурсию в эти дни... если нет, вы, конечно, получите переполнение одноименного стека для подходящих длинных строк.

Ответ 13

Вдохновленный Джон Скит, не-петлевая версия, которая не ударит ваш стек. Также полезной отправной точкой, если вы хотите использовать инфраструктуру 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;
}

Ответ 14

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

public static int numberOf(String target, String content)
{
    return (content.split(target).length - 1);
}

Ответ 15

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

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

Ответ 16

Также можно использовать сокращение в Java 8 для решения этой проблемы:

int res = "abdsd3$asda$asasdd$sadas".chars().reduce(0, (a, c) -> a + (c == '$' ? 1 : 0));
System.out.println(res);

Вывод:

3

Ответ 17

Полный образец:

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

Ответ 18

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

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

Ответ 19

Если вы используете фреймворк Spring, вы также можете использовать класс "StringUtils". Этот метод будет "countOccurrencesOf".

Ответ 20

Вы можете использовать функцию split() в одной строке кода

int noOccurence=string.split("#",-1).length-1;

Ответ 21

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

Ответ 22

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

Ответ 23

В то время как методы могут скрыть это, нет возможности считать без цикла (или рекурсии). Однако вы хотите использовать 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) не похоже на лучший способ.

Ответ 24

Где-то в коде что-то должно зацикливаться. Единственный путь вокруг этого - полное разворачивание цикла:

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

Ответ 25

Вот немного другое решение для рекурсии стиля:

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

Ответ 26

Почему бы просто не разбить на символ, а затем получить длину результирующего массива. длина массива всегда будет числом экземпляров + 1. Правильно?

Ответ 27

Следующий исходный код даст вам 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);
        }

    }
}

Ответ 28

int count = (line.length() - line.replace("str", "").length())/"str".length();

Ответ 29

Ну, с такой же задачей я наткнулся на эту тему. Я не видел ограничений языка программирования, так как groovy работает на java vm: Вот как я смог решить мою проблему с помощью Groovy.

"a.b.c.".count(".")

сделанный.

Ответ 30

Использование Коллекции 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.