Разбейте строку на токены и разделите токены на два отдельных массива - PullRequest
0 голосов
/ 19 октября 2018

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

Размер массивов определяется параметром емкости в функции.Массивы выделяются до вызова функции readBooks (), поэтому нет необходимости их динамически распределять.

Вот код, который у меня есть:

int readBooks (string filename, string titles[], string authors[], int books, int capacity){
    ifstream file;
    file.open (filename);
    if (file.fail()){
        return -1;
    }
    else{
        int i = 0;
        int j = 0;
        while (i < capacity){
            string line;
            getline (file, line);
            if (line.length() > 0){

            }
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Это было бы немного проще с использованием библиотек наддува, где вы можете проверить наличие нескольких разделителей.Однако вы можете использовать getline () для поиска разделителей конца строки, а затем использовать find () для поиска запятой.После того, как вы найдете запятую, вы должны обязательно пропустить ее до заголовка, а также обрезать все пробелы.

Дайте мне знать, если это имеет смысл.

#include <iostream>
#include <fstream>
#include <string>
#include "readBooks.h"

#include <algorithm>
#include <cctype>
#include <locale>

/* trim from start (in place) [Trim functions borrowed from 
 * /203635/kakoi-luchshii-sposob-obrezat-std-string] 
 */

static inline void ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
        return !std::isspace(ch);
    }));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
        return !std::isspace(ch);
    }).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
    ltrim(s);
    rtrim(s);
}


using namespace std;

int readBooks (string filename, string titles[], string authors[], int books, int capacity){
    ifstream file;
    file.open (filename);
    if (file.fail()){
        return -1;
    }
    else{
        int i = 0;
        string line;

        while(  i < books && i < capacity && getline(file,line) ) {
            // Find the position of the comma, and grab everything before it
            string author(line.begin(), find(line.begin(), line.end(), ','));
            trim(author);
            authors[i] = author;
            // Find position of first character after the ','
            string title(find(line.begin(), line.end(), ',') + 1, line.end());
            trim(title);
            titles[i] = title;
            i++; // increment our index
        }
    }
    file.close();
    return 0;
}

Вот пример main () для его вызова.

#include <iostream>
#include "readBooks.h"

int main() {

  const int capacity{1000};
  const int books{3};
  std::string authors[capacity];
  std::string titles[capacity];
  std::string filename{"booklist.txt"};

  int retval = readBooks(filename, titles, authors, books, capacity);

  return retval;
}
0 голосов
/ 19 октября 2018

Прежде всего, почему вы хотите использовать массивы выходных данных (std::string[]), если вы даже не уверены в размерах выходных данных.std::vector всегда лучшее решение.

void readBooks(std::string const& filename, std::vector<std::string> &titles, std::vector<std::string> &authors) {
    std::ifstream file;
    // .....
    // file is opened here
    // ....
    std::string temp;
    while (file) {
        if (!std::getline(file, temp, ','))
            throw std::exception("File is broken?");
        authors.push_back(temp);
        std::getline(file, temp, '\n');
        titles.push_back(temp); //make sure there is no space after ',', as it'd be included in the string.
        //To remove such a space temp.substr(1) can be used.
    }
}

Короче говоря, оно основано на параметре delimiter, равном std::getline().

РЕДАКТИРОВАТЬ: проверьте, когда файл заканчивается на ','был добавлен.

...