#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.
- Начните с инициализации обоих
EOF
. - Считывает символ в
current
. - Если current — это пробел или EOF (ну, все, что вы не считаете частью слова), а previous — это
z
или предыдущийy
, увеличьте количество. - Если
current
это EOF , распечатайтеcount
, и все готово. - Скопируйте значение в
current
intoprevious
. - Вернитесь к шагу 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
помощью , что немного снижает накладные расходы, но это не особенно важно.)