Консультация № 173263
14.10.2009, 09:29
0.00 руб.
0 14 3
Доброго времени суток, уважаемые эксперты!
Помогите решить одну задачку: «Дана строка, содержащая пробелы. Найдите, сколько в нем слов
Вход: На вход подается несколько строк. Входная строка должна считываться методом getline.
Выход: количество слов в первой из введенных строк.»

Обсуждение

давно
Старший Модератор
17042
808
14.10.2009, 09:53
общий
это ответ
Здравствуйте, Kwant!
Это простейший вариант решения.
Число слов в строке будем считать равным числу пробелов, разделяющих слова, плюс 1 (предполагается, что после последнего слова в строке пробела нет).
Число пробелов считаем, передвигаясь по символам первой строки в функции CheckGaps, которая и возвращает число пробелов. В остальном см. приложение.
Вывод программы:

Введите первую строку: Ко мне на заре в сновиденье
Введите вторую строку: Пришла моя мать... Не гони её
Введите третью строку: Криком своим, кукушка!
Первая строка содержит 6 слов.


Приложение:
#include <iostream>
#include <string>
using namespace std;
//---------------------------------------------------------
int CheckGaps(string &sCheckedString)
{
char cSymbol;
int i = 0;
int iGaps = 0; // Число пробелов строке - пока не считали.

while(i < sCheckedString.length()) // Пока не достигнут конец строки
{
cSymbol = sCheckedString.c_str()[i]; // перемещаемся по её символам.
if(cSymbol == ' ') iGaps++; // А вот и пробел - учитываем...
i++;
}

return iGaps;
}
//---------------------------------------------------------
int main()
{
string sCheckedString;
string sString1, sString2;
cout << "Введите первую строку: ";
getline(cin, sCheckedString);
cout << "Введите вторую строку: ";
getline(cin, sString1);
cout << "Введите третью строку: ";
getline(cin, sString2);

cout << "Первая строка содержит " << (CheckGaps(sCheckedString) + 1) << " слов." << endl;
return 0;
}
5
Об авторе:
We have but faith: we cannot know;
For knowledge is of things we see;
And yet we trust it comes from thee,
A beam in darkness: let it grow.
-----
https://www.linkedin.com/in/andreynkuznetsov
https://www.researchgate.net/profile/Andrey_Kuznetsov11
http://www.researcherid.com/rid/K-8824-2014
Неизвестный
14.10.2009, 10:09
общий
Благодарю за ответ
давно
Академик
20764
1861
14.10.2009, 10:41
общий
Dr_Andrew:
Ваш вариант считает пробелы, а это не то же самое, что и слова. Я так понимаю - задача учебная, поэтому вариант функции на plain C без библиотек (почти) для однобайтовых символов:
Код:

#include <ctype.h>
int word_count(const char *str) {
int wc = 0;
int in_word = 0;
for (; *str; ++str) {
if (in_word) {
in_word = !isspace(*str);
} else {
if (!isspace(*str)) {
++wc;
in_word = 1;
}
}
}
return wc;
}

Неизвестный
14.10.2009, 10:47
общий
это ответ
Здравствуйте, Kwant.
Программа. C++. MS VS 2008.
Код:
#include <iostream>
#include <string>
#include <locale>
#include <algorithm>
#include <functional>

using namespace std;

// Разделители слов. В данном случае пробел. Добавьте что считаете нужным.
const wchar_t delimiters[]=L" ";

// Подсчитывает кол. слов в строке
size_t wordsCount(const wstring& str)
{
size_t count=0;
// Индекс текущего символа
wstring::size_type cur=0;
// Ищем первый не разделитель и пока есть такие
while((cur=str.find_first_not_of(delimiters,cur))!=wstring::npos)
{
// Инкрементируем счетчик
++count;
// Ищем конец слова(разделитель)
cur=str.find_first_of(delimiters,cur);
}
return count;
}

// ---------------- Второй способ ---------------------------------------------------
// Функтор, используемый ниже, для проверки символа на предмет является ли он разделителем
class isDelimPred:public unary_function<wchar_t,bool>
{
public:
result_type operator()(argument_type ch)const
{
#pragma warning(disable:4800)
return iswspace(ch);
}
};

// Вторая функция делающая то же самое только слегка по другому
size_t wordsCount2(const wstring& str)
{
size_t count=0;
wstring::const_iterator cur=str.begin(),end=str.end();
while((cur=find_if(cur,end,not1(isDelimPred())))!=end)
{
++count;
cur=find_if(cur,end,isDelimPred());
}
return count;
}
// --------------------------------------------------------------------------------------


int main()
{
locale::global(locale("russian_russia.866"));
wcout<<L"Введите строку:"<<endl;
wstring str;
getline(wcin,str);
wcout<<L"Количество слов в строке:"<<wordsCount(str)<<endl;
system("PAUSE");
return 0;
}

Пример работы:
Код:
Введите строку:
Сколько же здесь слов?
Количество слов в строке:4


В программе 2 функции:
wordsCount() - подсчитывает количество слов в строке. Разделителями считаются символы входящие в строку delimiters.
wordsCount2() - для учета разделителей использует ф-ю iswspace(). Т.е. разделителями считается не только пробел, но и любые whitespaces. Для этого реализован функтор. Если Вам это не надо можете смело удалить.
давно
Старший Модератор
17042
808
14.10.2009, 10:51
общий
Хватов Сергей:
В принципе исходил из условия, понятого как "строка содержит слова, разделённые пробелами". Легче всего подсчитать пробелы-разделители и прибавить к этому числу 1 (последнее слово). Потому и написал, что решение простейшее. Впрочем, нетрудно и дополнить код проверкой на последний пробел, за которым не следует слово. Но иные варианты тоже имеют право на существование: выбирать пользователю. Почему бы Вам не дооформить код до конца и не подать ответом?
Об авторе:
We have but faith: we cannot know;
For knowledge is of things we see;
And yet we trust it comes from thee,
A beam in darkness: let it grow.
-----
https://www.linkedin.com/in/andreynkuznetsov
https://www.researchgate.net/profile/Andrey_Kuznetsov11
http://www.researcherid.com/rid/K-8824-2014
давно
Старший Модератор
17042
808
14.10.2009, 10:58
общий
Хватов Сергей:
Вижу решение от Micren: тоже направлено на поиск пробелов-разделителей. Решение лучше моего тем, что между словами могут встречаться более одного пробела, что программа учитывает.
Об авторе:
We have but faith: we cannot know;
For knowledge is of things we see;
And yet we trust it comes from thee,
A beam in darkness: let it grow.
-----
https://www.linkedin.com/in/andreynkuznetsov
https://www.researchgate.net/profile/Andrey_Kuznetsov11
http://www.researcherid.com/rid/K-8824-2014
давно
Посетитель
7438
7205
14.10.2009, 11:14
общий
Dr_Andrew:
Именно, только хотел на это указать...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
14.10.2009, 11:17
общий
Kwant:
Немного добавил к решению. Если оно надо.
Неизвестный
14.10.2009, 12:11
общий
Благодарю за ответы
Неизвестный
14.10.2009, 12:20
общий
Уважаемый Хватов Сергей, не могли бы вы добавить комментарии к своему примеру
давно
Академик
20764
1861
14.10.2009, 13:45
общий
Kwant:
Настоящие программисты не пишут комментарии - текст программы всё объясняет сам

in_word - состояние разбора - признак, находимся ли мы внутри слова то есть предыдущий символ был не пробел. Изначально мы не в слове
wc - счётчик слов. Увеличивается если текущий символ не пробел и мы не в слове
isspace() - библиотечная функция (или макрос). описанная в ctype.h и определяющая, является ли символ пустым (пробел, табуляция, перевод строки)
давно
Посетитель
7438
7205
14.10.2009, 15:30
общий
Хочу и я предложить свой вариант подсчета слов:
Код:
int WordsCount(string str)
{
int wc = 0; //счетчик
int fSpacePrev; //признак, является ли разделителем предыдущий символ
int fSpaceCurr=1; //признак, является ли разделителем текущий символ
// вначале считаем, что начало с разделителя

for (int i=0; i<str.size(); ++i) //по всем символам строки
{
fSpacePrev = fSpaceCurr; //сохраним текущее состояние, как предыдущее
fSpaceCurr = isspace(str.c_str()[i]); //проверим текущий символ на разделитель
//1 - разделитель, 0 - нет
wc += fSpacePrev && !fSpaceCurr; //самое интересное:
// увеличиваем счетчик слов только если
// предыдущее состояние - разделитель,
// а текущее - нет, т.е. в начале слова
}
return wc;
}
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
14.10.2009, 16:48
общий
Огромное вам всем спасибо
давно
Посетитель
7438
7205
14.10.2009, 17:32
общий
это ответ
Здравствуйте, Kwant.
Если класс string не нужен, а работать с char[],
то можно реализовать так, как в приложении.

Приложение:
#include <iostream>
#include <locale>

using namespace std;

//---------------------------------------------------------
int WordsCount(const char * str)
{
int wc = 0; //счетчик
int fSpacePrev; //признак, является ли разделителем предыдущий символ
int fSpaceCurr=1; //признак, является ли разделителем текущий символ
// вначале считаем, что начало с разделителя

int iLen = strlen(str);
for (int i=0; i<iLen; ++i) //по всем символам строки
{
fSpacePrev = fSpaceCurr; //сохраним текущее состояние, как предыдущее
fSpaceCurr = isspace(str[i]); //проверим текущий символ на разделитель
//1 - разделитель, 0 - нет
wc += fSpacePrev && !fSpaceCurr;//самое интересное:
// увеличиваем счетчик слов только если
// предыдущее состояние - разделитель,
// а текущее - нет, т.е. в начале слова
}
return wc;
}
//---------------------------------------------------------
int main()
{
char sCheckedString[80];
char sString1[80];
char sString2[80];

locale::global(locale("russian_russia.866"));

wcout << L"Введите первую строку: ";
cin.getline(sCheckedString,80,'\n');

wcout << L"Введите вторую строку: ";
cin.getline(sString1,80,'\n');

wcout << L"Введите третью строку: ";
cin.getline(sString2,80,'\n');

wcout << L"Первая строка содержит " << WordsCount(sCheckedString) << L" слов." << endl;
system("pause");
return 0;
}
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа