Токенизация текстового файла с частотой и вхождением строки.Использование C ++ - PullRequest
0 голосов
/ 14 сентября 2010

еще раз прошу помощи. Некоторое время я ничего не кодировал!

Теперь у меня есть текстовый файл, заполненный случайной тарабарщиной. У меня уже есть базовое представление о том, как я буду считать количество вхождений в слове.

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

Я уже получаю слова через следующий код:

vector<string> words;
string currentWord;

while(!inputFile.eof())
{
inputFile >> currentWord;
words.push_back(currentWord); 
}

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

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

Ответы [ 3 ]

3 голосов
/ 14 сентября 2010

Используйте std::map<std::string, int> для подсчета вхождений слов - int - это количество раз, сколько оно существует.

Если вам нужно как по строковому вводу, используйте std::getline(std::istream&, std::string&), например:

std::vector<std::string> lines;
std::ifstream file(...) //Fill in accordingly.
std::string currentLine;
while(std::getline(file, currentLine))
    lines.push_back(currentLine);

Вы можете разбить строку на части, сначала поместив ее в std::istringstream, а затем используя operator>>. (С другой стороны, вы могли бы собрать какой-то сплиттер, используя std::find и другие алгоритмические примитивы)

РЕДАКТИРОВАТЬ: это то же самое, что и в ответе @ dash-tom-bang, но изменено, чтобы быть корректным в отношении обработки ошибок:

vector<string> words;
int currentLine = 1; // or 0, however you wish to count...

string line;
while (getline(inputFile, line))
{
   istringstream inputString(line);
   string word;
   while (inputString >> word)
      words.push_back(pair(word, currentLine));
}
0 голосов
/ 14 сентября 2010

Коротко и сладко.

vector< map< string, size_t > > line_word_counts;

string line, word;
while ( getline( cin, line ) ) {
    line_word_counts.push_back();
    map< string, size_t > &word_counts = line_word_counts.back();

    istringstream line_is( line );
    while ( is >> word ) ++ word_counts[ word ];
}

cout << "'Hello' appears on line 5 " << line_word_counts[5-1]["Hello"]
     << " times\n";
0 голосов
/ 14 сентября 2010

Вам придется отказаться от чтения в string с, потому что operator >>(istream&, string&) отбрасывает пробел и содержимое пробела (== '\n' или != '\n', то есть вопрос ...) это то, что даст вам номера строк.

Здесь ООП может спасти день. Вам нужно написать класс, который будет выступать в качестве «внешнего интерфейса» для чтения из файла. Его работа будет состоять в том, чтобы буферизовать данные из файла и возвращать слова по одному для вызывающей стороны.

Внутри класса класс должен читать данные из файла блоком (скажем, 4096 байт) за раз. Тогда метод string GetWord() (да, возвращение по значению здесь хорошо) будет:

  • Сначала прочитайте все пробельные символы, стараясь увеличивать элемент lineNumber объекта каждый раз, когда он попадает в \n.
  • Затем прочитайте непробельные символы, поместив их в объект string, который вы будете возвращать.
  • Если не хватает материалов для чтения, прочитайте следующий блок и продолжайте.
  • Если вы нажмете конец файла, то у вас будет string - целое слово (которое может быть пустым), и его следует вернуть.
  • Если функция возвращает пустую строку, это говорит вызывающей стороне, что конец файла достигнут. (Файлы обычно заканчиваются пробельными символами, поэтому чтение пробельных символов не может означать, что слово будет позже.)

Затем вы можете вызвать этот метод в том же месте в вашем коде, что и строка cin >>, и остальной код не должен знать детали буферизации вашего блока.

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

...