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

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

a.b.c.d

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

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

Домашнее задание? Потому что в противном случае я не вижу необходимости избегать цикла.

PhiLho 09.11.2008 19:13

Не прочь от петель столько, сколько искать идиоматический однострочный.

Bart 17.11.2008 17:28

Циклы были созданы для такой проблемы, напишите цикл в общем классе Utility, а затем вызовите свой недавно созданный один лайнер.

che javara 02.09.2015 00:31

Аналогичный вопрос для строк: stackoverflow.com/questions/767759/…

koppor 16.04.2017 22:41

Просто чтобы указать - я ценю поиск однострочных, это весело и (как истинное преимущество) часто легко запоминается, но я хотел бы указать, что отдельный метод и цикл лучше практически во всех отношениях. - читабельность и даже производительность. Большинство из приведенных ниже «элегантных» решений не будут работать очень хорошо, потому что они включают реформирование строк / копирование памяти, тогда как цикл, который просто просматривал строку и подсчитывал вхождения, был бы быстрым и простым. Не то чтобы производительность, как правило, должна быть фактором, но не смотрите на однострочную строку над циклом и предполагайте, что она будет работать лучше.

Bill K 04.05.2017 20:41

Возможный дубликат Найти вхождения символов в строке Java

thSoft 11.01.2018 17:43

@thSoft В будущем, пожалуйста, выбирайте вопросы / ответы с более высокими оценками в качестве повторяющейся цели.

Mark Rotteveel 12.01.2018 00:52
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
580
7
912 640
46
Перейти к ответу Данный вопрос помечен как решенный

Ответы 46

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

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

for (int i = 0, l = haystack.length (); i <l; i ++) будьте добры к своему стеку

Chris 29.11.2009 16:43

(Я даже не уверен, откуда взялся бит "стек" комментария. Это не похоже на то, что ответ это является моим рекурсивным, что действительно неприятно для стека.)

Jon Skeet 29.11.2009 17:51

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

ShuggyCoUk 30.11.2009 14:15

Я думаю, что @Chris обеспокоен тем, что length() вызывается очень часто, что может повлиять на производительность при работе с большими строками. Предложение Криса сокращает доступ к length() до одного звонка.

sulai 12.06.2014 17:37

@sulai: ИМО, опасения Криса безосновательны перед JIT-оптимизацией банальный. Есть ли причина, по которой этот комментарий привлек ваше внимание сейчас, более трех лет спустя? Просто интересно.

Jon Skeet 12.06.2014 17:39

Вероятно, @sulai просто натолкнулся на вопрос, как и я (задаваясь вопросом, есть ли в Java для этого встроенный метод), и не заметил даты. Однако мне любопытно, как перемещение вызова length() за пределы цикла может повысить производительность хуже, как упомянул @ShuggyCoUk в нескольких комментариях.

JKillian 30.07.2014 06:19

Я согласен, что что-то должно зацикливаться, но это более кратко: for (int i = 0; (i = haystack.indexOf(needle, i)) >= 0; i++) { count++; }, конечно, можно критиковать за то, что он немного загадочен.

njlarsson 01.03.2016 18:32

@njlarsson: Значит, у вас есть петля внутри цикла, но это не так очевидно. И да, я бы сказал, что это намного труднее читать.

Jon Skeet 01.03.2016 19:01

@JonSkeet Полагаю, вы правы. Я думал, что «резко сокращает количество вызовов функций, если стрелка встречается редко», но я полагаю, что charAt будет встроен, если это критический код.

njlarsson 02.03.2016 11:33

хороший needle по аналогии с haystack;)

user7627726 18.05.2017 08:48

(Извините за комментарий к старому сообщению) Как хорошая привычка, я бы порекомендовал реализацию @Chris в комментарии выше, которая переводит вызов length() на этап инициализации. Помимо «меньшего количества вызовов функций», он также избегает нетривиальные бесконечные циклы.

Sunny Pun 03.12.2018 09:01

@SunnyPun: я бы сделал это в случаях, когда а) вычисление нетривиально - в этом случае я бы ожидал, что оно будет встроенным; б) есть шанс изменить повторяемую вещь. В этом случае, поскольку строки неизменяемы и мы не меняем значение haystack, я бы использовал эту версию.

Jon Skeet 03.12.2018 10:08

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

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

ну есть петля, но это невидимый :-)

- Йонатан

Если ваша строка не слишком длинная, вы получите OutOfMemoryError.

Spencer Kormos 09.11.2008 18:50

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

erickson 09.11.2008 20:43

Это использует indexOf, который будет зацикливаться ... но хорошая идея. Публикация действительно "просто рекурсивного" решения за минуту ...

Jon Skeet 09.11.2008 21:03

Если в нем больше вхождений, чем доступных слотов стека, у вас будет исключение переполнения стека;)

Luca C. 02.06.2014 20:19

Петля не опасна. Рекурсия неконтролируемой глубины действительно опасна.

Hardest 17.09.2020 17:54
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();

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

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

Мне нравится этот. Конечно, есть еще петля, которая должна быть.

The Archetypal Paul 09.11.2008 18:13

Обратите внимание, что вам нужно разделить это число, если вы хотите искать подстроки длиной> 1

rogerdpack 04.04.2012 03:11

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

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

Правильный. ReplaceAll (".") Заменит любой символ, а не только точку. ReplaceAll ("\\.") Сработало бы. Ваше решение более простое.

VonC 09.11.2008 19:20

jjnguy на самом деле сначала предложил replaceAll ("[^.]"), увидев мое решение "a.b.c.d" .split ("\\."). length-1. Но после пяти ударов я удалил свой ответ (и его комментарий).

VonC 09.11.2008 19:24

«... теперь у вас две проблемы» (обязательно). В любом случае, готов поспорить, что в replaceAll() и length() выполняются десятки циклов. Ну а если не видно, значит не существует; о)

Piskvor left the building 25.08.2010 15:22

replaceAll использует регулярное выражение, и он огромен для вычислений. Лучше простой цикл ...

robob 20.04.2011 16:50

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

mingfai 24.04.2011 03:14

@mingfai: действительно, но исходный вопрос заключается в том, чтобы сделать однострочник и даже без цикла (вы можете сделать цикл в одной строке, но это будет некрасиво!). Ставьте под вопрос вопрос, а не ответ ... :-)

PhiLho 26.04.2011 21:25

Мне нравится этот ответ, потому что он краток и прямолинеен.

user626607 22.06.2012 16:25

Я не могу поверить, что ответ с регулярным выражением имеет 37 голосов. Вы все уволены!

MK. 03.01.2013 00:36

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

Нет, хвостовая рекурсия, вероятно, будет в Java 7, но пока еще не получила широкого распространения. Эту простую прямую хвостовую рекурсию можно преобразовать в цикл во время компиляции, но материал Java 7 фактически встроен в JVM для обработки цепочки с помощью различных методов.

erickson 10.11.2008 23:11

У вас будет больше шансов получить хвостовую рекурсию, если ваш метод вернет вызов самому себе (включая параметр текущего итога), а не результат выполнения добавления.

Stephen Denne 20.03.2009 13:56

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

Я считаю это наиболее элегантным решением. Почему вы использовали toCharArray, а не charAt напрямую?

Panayotis 31.05.2017 11:29

Цикл с помощью char, по крайней мере, раньше был медленнее. Может зависеть и от платформы. Единственный способ узнать это - измерить разницу.

tcurdt 31.05.2017 17:00

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

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

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

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

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

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

Maarten Bodewes 30.08.2014 20:51
Ответ принят как подходящий

Мой идиоматический однострочник:

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

Зачем писать самому, когда он уже в общий язык?

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

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

Эквивалент Гуава: int count = CharMatcher.is('.').countIn("a.b.c.d"); ... Как ответил dogbane в повторяющемся вопросе.

Jonik 12.08.2013 21:00

Хотя я не буду отрицать это, это (а) требует сторонних библиотек и (б) дорого.

StephenBoesch 24.01.2014 01:24

Это только работа с пружинной рамой, которую нужно импортировать.

Isuru Madusanka 29.09.2015 13:45

если кому то нужно: grepcode.com/file/repo1.maven.org/maven2/commons-lang/…

cV2 27.11.2015 15:54

В каждой компании, в которой я работал, было дорого иметь множество плохо написанных и плохо обслуживаемых классов «* Utils». Часть вашей работы - знать, что доступно в Apache Commons.

AbuNassar 05.10.2016 17:58

Для Maven / Gradle: mvnrepository.com/artifact/org.apache.commons/commons-lang3/‌ 3.0

AutonomousApps 16.02.2017 01:55

У меня есть базовое java-решение, проверьте это: stackoverflow.com/questions/3763970/…

Banee Ishaque K 24.06.2017 05:02

Попробуйте этот метод:

StringTokenizer stOR = new StringTokenizer(someExpression, "||");
int orCount = stOR.countTokens()-1;

Голосовать против меня. Он не возвращает допустимые результаты во всех случаях, например, если мы считаем «a» в строке «a, a, a, a, a», он возвращает 3 вместо 5.

Greg Witczak 28.05.2015 18:05

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

Почему бы просто не разделить на символ, а затем получить длину результирующего массива. длина массива всегда будет равна числу экземпляров +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;
}

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

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

Самый простой способ. Умный. И работает на Android, где нет класса StringUtils

Jose_GD 06.11.2012 17:12

Это лучший ответ. Причина, по которой это лучший вариант, заключается в том, что вам не нужно импортировать другую библиотеку.

Alex Spencer 10.07.2013 00:03

Это не обязательно быстрее, чем другие решения, такие как StringUtils.countMatches, потому что ему нужно выделить некоторую память для возвращаемой строки. По-прежнему хорошее решение, когда производительность не критична.

lyomi 17.09.2013 09:27

Очень практично, но чертовски уродливо. Я не рекомендую это, так как это приводит к путанице в коде.

Daniel San 26.03.2014 02:54

Уродливый код можно свести к минимуму, сделав его методом в вашем собственном классе StringUtils. Тогда уродливый код находится ровно в одном месте, а везде хорошо читается.

RonR 05.06.2014 20:54

Это должно пройти строку три раз; сначала он должен вычислить длину, затем он должен заменить символы для подсчета (что также включает создание новой строки), затем он должен снова вычислить длину. Интересно, что такого плохого в цикле (очевидно, это вопрос не для Андреаса, а для OP)

Grodriguez 09.07.2014 16:00

Просто хочу добавить еще кое-что для новичков. Если у кого-то строка длиннее, чем ".", В этом случае разделите счет на длину строки, чтобы получить правильное количество этой подстроки.

Himanshu Aggarwal 20.10.2014 10:52

String.replace(String, String) не использует регулярные выражения? Разве . не является подстановочным знаком в регулярном выражении? Итак, почему бы при замене не создать пустую строку?

Jack 06.11.2014 19:15

Нет, String.replace не использует регулярное выражение. docs.oracle.com/javase/8/docs/api/java/lang/…

Andreas Wederbrand 06.11.2014 22:27

Метод цикла на много быстрее, чем этот. Особенно, если вы хотите подсчитать char вместо String (поскольку нет метода String.replace (char, char)). В строке из 15 символов я получаю разницу в 6049 нс против 26 739 нс (в среднем за 100 циклов). Необработанные числа - огромная разница, но с точки зрения восприятия ... она складывается. Избегайте выделения памяти - используйте цикл!

Ben 18.11.2014 18:41

String.replace (CharSequnce, CharSequence) действительно использует регулярное выражение (посмотрите этот исходный код OpenJDK: goo.gl/O9dQzg) Для замены 1 символа на 1 символ используйте String.replace (char, char) для повышения производительности. Он просто перебирает символы строки: goo.gl/2FbcWP

hoat4 04.04.2015 13:34

Еще одна интересная вариация этого метода - подсчет появления целой строки или символа: int count = (sourceString.length() - sourceString.replace(searchString, "").length())/searcString.length();

James Oltmans 23.04.2015 03:37

@Grodriguez, это неправильно, Java String не заканчивается нулем и не должен перебирать символы, чтобы определить его длину. Вместо этого он использует внутри себя массив символов. Array.length - это O (1).

Andy 23.04.2017 00:16

Я не говорил, что строки Java завершаются NUL, и не говорил, что для вычисления длины нужен цикл. В любом случае фактическая реализация String зависит от реализации.

Grodriguez 23.04.2017 17:16

Разве это не должно быть: int count = (line.length () - line.replace (".", "") .Length ()) / ".". Length (); предполагая, что вы хотите параметризовать строку "."?

mrg 11.12.2017 17:02

Что ж, этот ответ настолько смущающе прост, я бы даже не подумал об этом через тысячу лет ...

Max Belli 14.05.2018 10:02

Это очень неправильно, вы выделяете память для подсчета при линейном сканировании.

Hardest 17.09.2020 17:48

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

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

неправильный код, он не работает, когда я пытаюсь int instances = CharacterCounter.countOccurrences ("1", "101"); System.out.println (вхождения); // 1

jayesh 20.01.2014 10:32

Я фиксирую исправление для кода, работающего с той же логикой

MaanooAk 27.07.2017 10:06
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

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

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

Чтобы также подсчитать вхождения в конце строки, вам нужно будет вызвать split с аргументом отрицательного лимита, например: return (content.split(target, -1).length - 1);. По умолчанию вхождения в конце строки опускаются в массиве в результате split (). См. Доку

vlz 04.05.2014 16:08

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

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

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

Отдать немного любви к этому, потому что это единственный, кто делает один проход по струне. Я ДЕЙСТВИТЕЛЬНО забочусь о производительности.

StephenBoesch 23.01.2014 00:19
charAt выполняет итерацию по 16-битным кодовым точкам, а не по символам! char в Java не является символом. Итак, этот ответ подразумевает, что не должно быть символа Unicode с высоким суррогатом, равным кодовой точке delim. Я не уверен, что это правильно для точки, но в целом это может быть неверно.
ceving 22.07.2014 21:25

Следующий исходный код даст вам количество вхождений данной строки в слово, введенное пользователем: -

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

    }
}
 public static int countSubstring(String subStr, String str) {

    int count = 0;
    for (int i = 0; i < str.length(); i++) {
        if (str.substring(i).startsWith(subStr)) {
            count++;
        }
    }
    return count;
}

Почему вы пытаетесь избежать петли? Я имею в виду, что вы не можете сосчитать точки «numberOf», не проверив каждый отдельный символ строки, и если вы вызовете любую функцию, она каким-то образом зациклится. То есть String.replace должен выполнить цикл, проверяющий, появляется ли строка, чтобы она могла заменить каждое отдельное вхождение.

Если вы пытаетесь уменьшить использование ресурсов, вы этого не сделаете, потому что вы создаете новую строку только для подсчета точек.

Теперь, если мы говорим о рекурсивном методе «введите код здесь», кто-то сказал, что он не сработает из-за OutOfMemmoryException, я думаю, он забыл StackOverflowException.

Итак, мой метод будет таким (я знаю, что он похож на другие, но для этой проблемы требуется цикл):

public static int numberOf(String str,int c) {
    int res=0;
    if (str==null)
        return res;
    for(int i=0;i<str.length();i++)
        if (c==str.charAt(i))
            res++;
    return res;
}
String s = "a.b.c.d";
long result = s.chars().filter(ch -> ch == '.').count();

Проголосуйте + за нативное решение.

Scadge 23.03.2016 16:31

Мое "идиоматическое однострочное" решение:

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

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

В этом посте есть более старое решение, подобное этому.

JCalcines 05.02.2014 13:24

Потому что это решение действительно неэффективно

András 14.05.2015 12:41

Это создает дополнительную строку только для подсчета. Понятия не имею, почему кто-то предпочел бы это StringUtils, если StringUtils - вариант. Если это не вариант, им следует просто создать простой цикл for в служебном классе.

crush 28.05.2016 23:15
int count = (line.length() - line.replace("str", "").length())/"str".length();

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

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

Тогда использование .codePoints() вместо .chars() будет поддерживать любое значение Unicode (включая те, которые требуют суррогатных пар).

Luke Usherwood 14.08.2014 18:40

А как насчет ниже рекурсивного алгоритма, который также является линейным временем.

import java.lang.*;
import java.util.*;

class longestSubstr{

public static void main(String[] args){
   String s = "ABDEFGABEF";


   int ans=calc(s);

   System.out.println("Max nonrepeating seq= "+ans);

}

public static int calc(String s)
{//s.s
      int n=s.length();
      int max=1;
      if (n==1)
          return 1;
      if (n==2)
      {
          if (s.charAt(0)==s.charAt(1)) return 1;
          else return 2;


      }
      String s1=s;
    String a=s.charAt(n-1)+"";
          s1=s1.replace(a,"");
         // System.out.println(s+" "+(n-2)+" "+s.substring(0,n-1));
         max=Math.max(calc(s.substring(0,n-1)),(calc(s1)+1));


return max;
}


}


</i>

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

Обратите внимание, что если производительность является какой-либо проблемой, используйте вместо этого Ответ Джона Скита. Этот вариант немного более обобщен и поэтому, на мой взгляд, немного более читабелен (и, конечно же, его можно использовать повторно для строк и шаблонов).

public static int countOccurances(char c, String input) {
    return countOccurancesOfPattern(Pattern.quote(Character.toString(c)), input);
}

public static int countOccurances(String s, String input) {
    return countOccurancesOfPattern(Pattern.quote(s), input);
}

public static int countOccurancesOfPattern(String pattern, String input) {
    Matcher m = Pattern.compile(pattern).matcher(input);
    int count = 0;
    while (m.find()) {
        count++;
    }
    return count;
}
public class OccurencesInString { public static void main(String[] args) { String str = "NARENDRA AMILINENI"; HashMap occur = new HashMap(); int count =0; String key = null; for(int i=0;i<str.length()-1;i++){ key = String.valueOf(str.charAt(i)); if (occur.containsKey(key)){ count = (Integer)occur.get(key); occur.put(key,++count); }else{ occur.put(key,1); } } System.out.println(occur); } }

Я вижу, что этот ответ усечен, поэтому, возможно, вам не нужны следующие предложения. Но на всякий случай: 1) Не вставляйте просто код. Поясните немного, расскажите, почему вы считаете это хорошим решением. 2) Отформатируйте свой код: stackoverflow.com/editing-help

cornuz 21.11.2014 14:16

Ответы, содержащие только код, автоматически помечаются как низкое качество и поэтому не приветствуются при stackoverflow. В будущем, пожалуйста, приукрасите свой ответ подробностями и объясните, почему это решение вопроса. Это помогает другим пользователям. Также - вы никогда не слышали о возврате каретки ??

tom redfern 21.11.2014 14:47

Я попытался решить ваш вопрос с помощью оператора switch, но мне все еще нужен цикл for для анализа строки. не стесняйтесь комментировать, могу ли я улучшить код

public class CharacterCount {
public static void main(String args[])
{
    String message = "hello how are you";
    char[] array=message.toCharArray();
    int a=0;
    int b=0;
    int c=0;
    int d=0;
    int e=0;
    int f=0;
    int g=0;
    int h=0;
    int i=0;
    int space=0;
    int j=0;
    int k=0;
    int l=0;
    int m=0;
    int n=0;
    int o=0;
    int p=0;
    int q=0;
    int r=0;
    int s=0;
    int t=0;
    int u=0;
    int v=0;
    int w=0;
    int x=0;
    int y=0;
    int z=0;


    for(char element:array)
    {
        switch(element)
        {
        case 'a':
        a++;
        break;
        case 'b':
        b++;
        break;
        case 'c':c++;
        break;

        case 'd':d++;
        break;
        case 'e':e++;
        break;
        case 'f':f++;
        break;

        case 'g':g++;
        break;
        case 'h':
        h++;
        break;
        case 'i':i++;
        break;
        case 'j':j++;
        break;
        case 'k':k++;
        break;
        case 'l':l++;
        break;
        case 'm':m++;
        break;
        case 'n':m++;
        break;
        case 'o':o++;
        break;
        case 'p':p++;
        break;
        case 'q':q++;
        break;
        case 'r':r++;
        break;
        case 's':s++;
        break;
        case 't':t++;
        break;
        case 'u':u++;
        break;
        case 'v':v++;
        break;
        case 'w':w++;
        break;
        case 'x':x++;
        break;
        case 'y':y++;
        break;
        case 'z':z++;
        break;
        case ' ':space++;
        break;
        default :break;
        }
    }
    System.out.println("A "+a+" B "+ b +" C "+c+" D "+d+" E "+e+" F "+f+" G "+g+" H "+h);
    System.out.println("I "+i+" J "+j+" K "+k+" L "+l+" M "+m+" N "+n+" O "+o+" P "+p);
    System.out.println("Q "+q+" R "+r+" S "+s+" T "+t+" U "+u+" V "+v+" W "+w+" X "+x+" Y "+y+" Z "+z);
    System.out.println("SPACE "+space);
}

}

Это как можно дальше от однострочника. Ужасный.

james.garriss 09.12.2015 22:36

Попробуйте этот код:

package com.java.test;

import java.util.HashMap;
import java.util.Map;

public class TestCuntstring {

    public static void main(String[] args) {

        String name = "Bissssmmayaa";
        char[] ar = new char[name.length()];
        for (int i = 0; i < name.length(); i++) {
            ar[i] = name.charAt(i);
        }
        Map<Character, String> map=new HashMap<Character, String>();
        for (int i = 0; i < ar.length; i++) {
            int count=0;
            for (int j = 0; j < ar.length; j++) {
                if (ar[i]==ar[j]){
                    count++;
                }
            }
            map.put(ar[i], count+" no of times");
        }
        System.out.println(map);
    }

}

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

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

Готово.

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

   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) Использование заменить все (случай 1)

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

5) Использование заменить все (случай 2)

int replaceAllCase2 = testString.length() - testString.replaceAll("\\.", "").length();
System.out.println("replaceAll (second case) = " + replaceAllCase2);

6) Использование расколоть

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 он будет работать, но для a ... 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

Напечатанные строки не совпадают с приведенными выше, и порядок сначала самый быстрый, что, по крайней мере, усложняет поиск. В остальном хороший ответ!

Maarten Bodewes 01.06.2017 14:05

случай 2, обобщенный для кодовых точек, которым требуется более одной кодовой единицы UTF-16: "1?2?3 has 2".codePoints().filter((c) -> c == "?".codePointAt(0)).count()

Tom Blodget 02.08.2018 01:50
StringUtils.countMatches Apache Commons перебирает индексы и использует charAt; StringUtils.countOccurencesOf Spring Framework многократно использует indexOf. (String.indexOf OpenJDK в основном использует charAt в цикле.)
Solomon Ucko 18.08.2020 23:29

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

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

Split действительно создает массив строк, на что уходит много времени.

Palec 19.05.2016 20:03

Вы правы, это проблема правда. С другой стороны, он позволяет избежать использования сторонней библиотеки в вашем проекте (если это еще не сделано). Это зависит от того, что вы хотите сделать, и от ожидаемой производительности.

Benj 14.06.2016 10:23

Это решение НЕ будет включать завершающие пустые совпадения, потому что аргумент limit установлен в ноль в этом перегруженном вызове метода разделения. Пример: "1##2#3#####".split("#") даст только массив размера 4 ([0:"1";1:""; 2:"2"; 3:"3"]) вместо размера 9 ([0:"1"; 1:""; 2:"2"; 3:"3"; 4:""; 5:""; 6:""; 7:""; 8:""]).

klaar 31.08.2016 18:05

Если вы хотите посчитать «нет». того же символа в строке «SELENIUM» или вы хотите напечатать уникальные символы строки «SELENIUM».

public class Count_Characters_In_String{

     public static void main(String []args){

        String s = "SELENIUM";
        System.out.println(s);
        int counter;

       String g = "";

        for( int i=0; i<s.length(); i++ ) { 

        if (g.indexOf(s.charAt(i)) == - 1){
           g=g+s.charAt(i); 
          }

       }
       System.out.println(g + " ");



        for( int i=0; i<g.length(); i++ ) {          
          System.out.print(",");

          System.out.print(s.charAt(i)+ " : ");
          counter=0; 
          for( int j=0; j<s.length(); j++ ) { 

        if ( g.charAt(i) == s.charAt(j) ) {
           counter=counter+1;

           }      

          }
          System.out.print(counter); 
       }
     }
}

/******************** ВЫХОД **********************/

СЕЛЕН

СЕЛНИУМ

S: 1, E: 2, L: 1, E: 1, N: 1, I: 1, U: 1

Самый простой способ получить ответ:

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

Этот фрагмент кода не возвращает правильное количество точек для заданного ввода «a.b.c.»

dekaru 07.11.2018 02:09

@dekaru Не могли бы вы вставить свое жало в комментарий, чтобы мы могли посмотреть.

Amar Magar 14.11.2018 10:19

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

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

Выход:

3

Использование Коллекции Eclipse

int count = Strings.asChars("a.b.c.d").count(c -> c == '.');

Если у вас есть более одного символа для подсчета, вы можете использовать CharBag следующим образом:

CharBag bag = Strings.asChars("a.b.c.d").toBag();
int count = bag.occurrencesOf('.');

Примечание: я являюсь приверженцем коллекций Eclipse.

String[] parts = text.split(".");
int occurances = parts.length - 1;

" It's a great day at O.S.G. Dallas! "
     -- Famous Last Words

Что ж, это случай знания вашей Java, особенно вашего базового понимания классов коллекций, уже доступных в Java. Если вы просмотрите всю публикацию здесь, есть почти все, кроме объяснения Стивена Хокинга о Происхождении Вселенной, мягкой обложки Дарвина об эволюции и выбора актерского состава Джина Родденберри из Звездного пути о том, почему они пошли с Уильямом Шатнером, не дожидаясь, как это сделать это быстро и легко ...

... мне нужно больше говорить?

Можете ли вы добавить к этому объяснение вместо того, чтобы просто размещать код?

MLavrentyev 29.07.2017 22:10

Это создает массив parts, который необходимо выделить, а затем собрать мусор. Совершенно ненужные накладные расходы. Попробуйте сделать это в плотном цикле.

Palec 31.07.2017 14:59

Кроме того, не следует ли его разбивать ("\\.") Для разбивки по точкам?

Tobias Reich 25.01.2018 17:58

Кроме того, если строка "foo." результат будет таким же, как если бы строка была «полосой»

dekaru 07.11.2018 02:08
public static void getCharacter(String str){

        int count[]= new int[256];

        for(int i=0;i<str.length(); i++){


            count[str.charAt(i)]++;

        }
        System.out.println("The ascii values are:"+ Arrays.toString(count));

        //Now display wht character is repeated how many times

        for (int i = 0; i < count.length; i++) {
            if (count[i] > 0)
               System.out.println("Number of " + (char) i + ": " + count[i]);
        }


    }
}

Кусок кода - не лучший ответ. Может быть, попытайтесь расширить это рассуждениями, объяснениями, подводными камнями и т. д.

user1531971 01.08.2018 22:44

Java не использует ASCII; char - это кодовая единица UTF-16. Диапазон значений: 0..Character.MAX_VALUE. Ваш алгоритм работает, если целью является подсчет случаев использования кодовых единиц UTF-16.

Tom Blodget 02.08.2018 01:47

Использование Java 8 и HashMap без какой-либо библиотеки для подсчета всех разных символов:

private static void countChars(String string) {
    HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
    string.chars().forEach(letter -> hm.put(letter, (hm.containsKey(letter) ? hm.get(letter) : 0) + 1));
    hm.forEach((c, i) -> System.out.println(((char)c.intValue()) + ":" + i));
}

используйте лямбда-функцию, которая удаляет все символы для подсчета
счетчик - это разница между длиной до и после

String s = "a.b.c.d";
int count = s.length() - deleteChars.apply( s, "." ).length();  // 3

найдите здесь deleteChars


если вам нужно подсчитать появление более чем одного символа, это можно сделать одним махом:
например. для bc и .:

int count = s.length() - deleteChars.apply( s, "bc." ).length();  // 5

Гораздо более простым решением было бы просто разделить строку на основе символа, с которым вы ее сопоставляете.

Например,

int getOccurences(String characters, String string) { String[] words = string.split(characters); return words.length - 1; }

Это вернет 4 в случае: getOccurences("o", "something about a quick brown fox");

Проблема здесь в том, что нужно выделить массив, что ужасно медленно.

Palec 07.01.2020 09:23

Это то, что я использую для подсчета вхождений строки.

Надеюсь, кто-то сочтет это полезным.

    private long countOccurrences(String occurrences, char findChar){
        return  occurrences.chars().filter( x -> {
            return x == findChar;
        }).count();
    }

однострочное лямбда
без необходимости во внешней библиотеке. Создает карту с количеством каждого символа:

Map<Character,Long> counts = "a.b.c.d".codePoints().boxed().collect(
    groupingBy( t -> (char)(int)t, counting() ) );

получает: {a=1, b=1, c=1, d=1, .=3}
количество определенного символа, например. '.' отдан:
counts.get( '.' )

(Я также пишу лямбда-решение из болезненного любопытства, чтобы узнать, насколько медленным является мое решение, желательно от человека с 10-строчным решением.)

Другие вопросы по теме