C подсчитывает количество слов в строке, которые заканчиваются на ‘y’ или ‘z’

#c

#c

Вопрос:

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

Например:

«день феса» -> 2

«день fyyyz» -> 2

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

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

Этот код подсчитывает количество слов в строке:

 int words = 0;
bool connectedLetter;
   for (auto c : s)
   {
      if (c == ' ')
      {
        connectedLetter = false; 
      }
      if ( c != ' ' amp;amp; connectedLetter == false)
      {
           words;
         connectedLetter = true;
      }
 

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

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

 int vowels{0};
for (auto c : s)
{
   if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' 
   || c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U')
   {
        vowels;
   }
}
 

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

  auto len = s.size();
   
   for (auto i = 0; i < len; i = i   2)
   {
      result  = s.at(i);
   }
 

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

Комментарии:

1. Мы не можем сделать за вас домашнее задание. Можете ли вы показать нам какой-нибудь код, который вы пробовали?

2. Как насчет чего-то вроде «понедельник, вторник, среда». Это 0 или 3?

3. @Tas я почти уверен, что это будет 3! Потому что я смотрю только на последнюю букву в слове

4. Это не обязательно поиск слов, но части строк, которые заканчиваются на ‘y’ или ‘z’? Возможно, для начала нужно сначала найти нужные буквы, а не пробел, разделяющий слова.

Ответ №1:

Вы также можете использовать существующие функции C , которые предназначены для выполнения того, что вы хотите.

Решение состоит в том, чтобы воспользоваться базовыми функциями IOstream. Возможно, вы знаете, что оператор извлечения >> будет извлекать слова из потока (like std::cin или любого другого потока), пока он не достигнет следующего пробела.

Таким образом, чтение слов просто:

 std::string word{}; std::cin >> word;
 

будет считано полное слово из std::cin .

Хорошо, у нас есть a std::string и нет потока. Но здесь C поможет вам с std::istringstream . Это преобразует a std::string в объект stream . Затем вы можете использовать все функциональные возможности iostream с этим stringstream .

Затем для подсчета элементов, следуя специальному требованию, у нас есть стандартный алгоритм из библиотеки C : std::count_if .

Он ожидает итератор begin и end. И здесь мы просто используем std::istream_iterator which вызовет оператор извлечения >> для всех строк, которые находятся в потоке.

С помощью лямбды, заданной для std::count_if , мы проверяем, соответствует ли слово требуемому условию.

Тогда мы получим очень компактный фрагмент кода.

 #include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <iterator>

int main() {
    // test string
    std::string testString{ "day fyyyz" };

    // We want to extract words from the string, so, convert string to stream.
    std::istringstream iss{ testString };

    // count words, meeting a special condition
    std::cout << std::count_if(std::istream_iterator<std::string>(iss), {},
        [](const std::stringamp; s) { return s.back() == 'y' || s.back() == 'z'; });

    return 0;
}
 

Конечно, есть множество других возможных решений.


Редактировать

Пит Беккер попросил более гибкое решение. Также здесь C предлагает специальную функциональность. Std::sregex_token_iterator .

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

В результате получается еще более простой фрагмент кода:

 #include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <regex>

const std::regex re{ R"(w [zy])" };

int main() {
    // test string
    std::string s{ "day, fyyyz, abc , zzz" };

    // count words, meeting a special condition
    std::cout << std::vector(std::sregex_token_iterator(s.begin(), s.end(), re), {}).size();

    return 0;
}
 

Комментарии:

1. Довольно хорошее объяснение. 1. Теперь, для получения бонусных очков, заставьте его работать на "day, fyyz" . <g> (Это, кажется, выходит за рамки первоначального вопроса)

2. @PeteBecker: Добавлено . . .

Ответ №2:

Если вы не собираетесь использовать массив (или что-то подобное, например, a string ), вероятно, проще всего использовать два int s. Для простоты давайте назовем их current и previous . Вам также понадобится a count , который вы захотите инициализировать равным 0.

  1. Начните с инициализации обоих EOF .
  2. Считывает символ в current .
  3. Если current — это пробел или EOF (ну, все, что вы не считаете частью слова), а previous — это z или предыдущий y , увеличьте количество.
  4. Если current это EOF , распечатайте count , и все готово.
  5. Скопируйте значение в current into previous .
  6. Вернитесь к шагу 2.

Комментарии:

1. Спасибо за ответ! Но, боюсь, я понятия не имею, что такое EOF?

2. @Michele: это означает «Конец файла» — все, что вы получаете, чтобы сигнализировать о том, что вы достигли конца файла (а при вводе-выводе в стиле C это буквально называется EOF ).

Ответ №3:

std::string намного умнее, чем многие думают. В частности, он имеет функции-члены find_first_of , find_first_not_of , find_last_of , и find_last_not_of которые очень полезны для простого синтаксического анализа. Я бы подошел к этому так:

 std::string str = "fez day"; // for example

std::string targets = "yz";
int target_count = 0;
char delims = ' ';
std::string::pos_type pos = str.find_first_not_of(delims);
while (pos < str.length()) {
    pos = str.find_first_of(delims, pos);
    if (pos == std::string::npos)
        pos = str.length();
    if (targets.find(str[pos-1] != std::string::npos)
          target_count;
    pos = str.find_first_not_of(delims, pos);
}
std::cout << target_count << 'n';
 

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

 char delims = ' ';
 

Для

 std::string delims = " ,";
 

или для

 const char* delims = " ,"; // my preference
 

и если мне нужно изменить символы, которые я ищу, просто измените содержимое targets . (На самом деле, я бы использовал const char* targets = "xy"; и выполнял поиск с std::strchr помощью , что немного снижает накладные расходы, но это не особенно важно.)