Я очень запутался в том, как анализировать несколько разделителей, используя getline и strtok в С++

Мой код размещен ниже. Я хочу иметь возможность анализировать с помощью разделителей "()" и преобразовывать строки в целые числа в cpp.

while(getline(fin, line))
{
    x  = atoi((strtok(line.c_str(),'(,)'));
    xx = atoi((strtok(NULL,"(),"));
    xxx = atoi((strtok(NULL,"(),")));
    cout << x << "    " << xx << "    " << xxx << "\n";
}

но по какой-то причине я получаю следующие ошибки

GraphTest.cpp: 134: ошибка: неверное преобразование из «const char*» в «char*»

GraphTest.cpp: 134: ошибка: инициализация аргумента 1 «char * strtok (char *, const char *)»

.c_str должен преобразовать мою строку в строку типа c, что позволит мне использовать функции atoi и strtok. Я очень смущен и буду признателен за любую помощь.


person crazyinfinitus    schedule 02.12.2014    source источник
comment
похоже, у вас нетривиальная грамматика. выберите подходящий инструмент для лексирования и синтаксического анализа (например, flex+bison или boost spirit, ...).   -  person Karoly Horvath    schedule 02.12.2014
comment
'(,)' неправильно. Должно быть "(,)".   -  person Captain Obvlious    schedule 02.12.2014
comment
c_str() возвращает const char*, предполагается, что это постоянный немодифицируемый указатель на строковый внутренний буфер. strotok() изменяет входную строку для выполнения токенизации (поэтому он принимает char* вместо const char*), то просто так делать нельзя.   -  person Adriano Repetti    schedule 02.12.2014
comment
Это случай проблемы XY; вы используете неправильные инструменты для работы. Сделайте шаг назад и расскажите нам, как выглядят ваши входные данные и каков желаемый результат.   -  person Julian    schedule 24.03.2015


Ответы (2)


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

string getlineMultDelimiter(istream &is, string dlm, bool includeDelimiter)
{
    string str;
    char c;
    bool found = false;

    while (!found && is)
    {
        for (size_t i = 0; i < dlm.length() && !found; ++i)
            found = dlm[i] == is.peek();

        if (!found || includeDelimiter)
        {
            is.get(c);
            str += c;
        }
    }
    return str;
}

Он будет использовать все символы в строке dlm в качестве разделителя, и вы можете выбрать, включать ли разделитель в возвращаемую строку или нет.

person nickeb96    schedule 23.03.2015

Он не компилируется, потому что c_str() возвращает const char*, он должен быть постоянным указателем на немодифицируемый внутренний буфер string. С другой стороны, strtok() принимает char*, потому что он изменяет свою входную строку.

Теперь у вас есть два варианта: получить пригодную для использования строку C из strtok() или переписать все на C++.

Создайте новую модифицируемую строку C из вашей строки C++:

char* modifiableLine = strdup(line.c_str());

x  = atoi((strtok(modifiableLine, "(,)"));
// Other processing

free(modifiableLine);

Вы можете сделать это, если вам нужно хранить большой объем кода C внутри функции/класса C++. Лучшее решение — использовать то, что предлагает стандартная библиотека C++ (также отбрасывая функцию atoi() C, если C++ 11). Давайте сначала напишем вспомогательную функцию:

int readNextInt(istringstream& is, const string& delimiters) {
    string token;

    if (getline(is, token, delimiters))
        return stoi(token);

    return 0; // End of stream?
}

Используется следующим образом:

istringstream is(line)
x = readNextInt(is, "(),");
xx = readNextInt(is, "(),");
xxx = readNextInt(is, "(),");

Обратите внимание, что стандартная функция C++ getline() не принимает параметр string для разделителей, а принимает только один char, только тогда вам нужно написать свою собственную перегруженную версию. Взгляните на этот пост для хорошей и приятной возможной реализации (вы также можете просто заменить getline() на is >> token после is.imbue(), см. пример).

Ну... если вы уже используете Boost, вы можете просто использовать boost::tokenizer.

person Adriano Repetti    schedule 02.12.2014