C++ Чтение слов из текстового файла, слово за словом или символ за символом

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

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

Это моя последняя попытка: любая помощь была бы потрясающей или ссылка на учебник о том, как читать из входного файла слово за словом. (Слово, представляющее собой альфа-символы a-z и '(не) заканчивается пробелом, запятой, точкой, ; , : , ect....

void GetNextWord()
{
    string word = "";
    char c;

    while(inFile.get(c))
    {
        while( c > 64 && c < 123 || c == 39)
        {
            if((isupper(c)))
            {
                c = (tolower(c));
            }
            word = word + c;
        }
        outFile << word;
    }
}

person Matt Swezey    schedule 15.09.2010    source источник
comment
Кроме того, поместите скобки в свои условия while, чтобы четко определить их.   -  person Sidharth Panwar    schedule 15.09.2010
comment
НЕ используйте магические числа, они не переносимы. Используйте «A» или «Z» или что-то еще, что должно быть 39.   -  person Martin York    schedule 15.09.2010
comment
Научитесь использовать отладчик или поместите std::cout << "c " << (int)c << '\n';, std::cout << "word is now '" << word << "'\n"; и т. д. в свою функцию, чтобы вы могли видеть каждый шаг, который она делает. Навыки устранения неполадок гораздо важнее, чем ответ на этот вопрос.   -  person Tony Delroy    schedule 15.09.2010
comment
Содержит ли файл слова, написанные через дефис (имеются в виду слова, которые идут через разрывы строк)?   -  person Björn Pollex    schedule 15.09.2010


Ответы (5)


Ваша логика неверна. Внутренний цикл выполняется до тех пор, пока c не изменится, и в нем нет ничего, что могло бы изменить c.

А зачем тебе две петли? Я думаю, вы можете быть смущены тем, должна ли эта функция читать следующее слово или все слова. Попробуйте разделить эти проблемы, поместить их в разные функции (одна из которых вызывает другую). Я считаю, что проще всего подходить к таким проблемам в порядке сверху вниз:

while(inFile.good()) {
  std::string word = GetNextWord(inFile);
  if(!word.empty())
    std::cout << word << std::endl;
}

Теперь заполните пробелы, определив GetNextWord() для чтения всего до границы следующего слова.

person sbi    schedule 15.09.2010
comment
Я попробую и отчитаюсь о результатах, спасибо - person Matt Swezey; 16.09.2010


Лично мне нравится читать ввод с std::getline(std::istream&, std::string&) (в заголовке <string>, но вы конечно, также потребуется #include заголовок потока).

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

Кишки будут примерно такими:

std::string buffer;
while (std::getline(std::cin, buffer) {
// break each line into words, according to problem spec
}
person Max Lybbert    schedule 15.09.2010
comment
Это может быть проблематично, если в тексте есть слова, написанные через дефис. - person Björn Pollex; 15.09.2010
comment
Слово с дефисом, такое как обратное рассеяние, не имеет значения, поскольку спецификация задачи определяет, считается ли это одним словом или двумя. Однако, если я правильно понимаю Space_C0wb0y, слова, написанные через дефис для продолжения на следующей строке, потребуют больше логики, чем то, что я показал. Поскольку эта программа очень похожа на домашнюю работу, я сомневаюсь, что это будет правильный ввод, но если это так, то потребуется обработка такого ввода. - person Max Lybbert; 16.09.2010

я использую

// str is a string that holds the line of data from ifs- the text file.
// str holds the words to be split, res the vector to store them in.
while( getline( ifs, str ) ) 
    split(str, res);


void split(const string& str, vector<string>& vec)
{
    typedef unsigned int uint;

    const string::size_type size(str.size());
    uint start(0);
    uint range(0);

 /* Explanation: 
  * Range - Length of the word to be extracted without spaces.
  * start - Start of next word. During initialization, starts at space 0.
  * 
  * Runs until it encounters a ' ', then splits the string with a substr() function,
  * as well as making sure that all characters are lower-case (without wasting time
  * to check if they already are, as I feel a char-by-char check for upper-case takes
  * just as much time as lowering them all anyway.                                       
 */
    for( uint i(0); i < size; ++i )
    {
        if( isspace(str[i]) )
        {
            vec.push_back( toLower(str.substr(start, range + 1)) );
            start = i + 1;
            range = 0;
        } else
            ++range;
    }
    vec.push_back( toLower(str.substr(start, range)) );
}

Я не уверен, что это особенно полезно для вас, но я попробую. Функция toLower — это быстрая функция, которая просто использует функцию ::toLower(). Это читает каждый символ до пробела, а затем заполняет его вектором. Я не совсем уверен, что вы имеете в виду под char под char.

Вы хотите извлечь символ слова по времени? Или вы хотите проверять каждый символ по мере продвижения? Или вы имеете в виду, что хотите извлечь одно слово, закончить, а затем вернуться? Если это так, я бы 1) все равно порекомендовал вектор и 2) дайте мне знать, чтобы я мог реорганизовать код.

person IAE    schedule 15.09.2010
comment
мой первоначальный план состоял в том, чтобы читать слово, символ за символом за раз, и когда он попадает в пробел или любой знак препинания, он перестает получать слово, превращает все эти символы в строку и отправляет эту строку в мою другую функцию для дальнейшей обработки . переводя все прописные буквы в строчные. Т.е. не стал бы ненавидеть. - person Matt Swezey; 16.09.2010

Что завершит ваш внутренний цикл, если c == 'a'? Значение ASCII для «а» равно 97.

person Andrew Bainbridge    schedule 15.09.2010
comment
если c == a, то внутренний цикл не завершится. внутренний цикл завершается, если char не является A-Z, a-z и ' - person Matt Swezey; 16.09.2010