Токенизация строки с "", разбив на "." - PullRequest
0 голосов
/ 31 марта 2020

Обнаружена проблема, когда я пытаюсь токенизировать строку, полученную из getline из консоли. Это ломается в "" так же как "." когда я только хочу, чтобы это сломалось в "".

Вот метод, который я создал для этой проблемы:

queue<string> getStringList(string list, string delimiter) {
    queue<string> values;
    size_t pos = 0;
    string token;
    while ((pos = list.find(delimiter) != string::npos))
    {
        token = list.substr(0, pos);
        std::cout << token << std::endl;
        values.push(token);
        list.erase(0, pos + delimiter.length());
    }
    std::cout << list << endl;
    return values;
}

Пример ввода:

cid Arrival_time dir_original dir_target

0 1,1 ^ ^

1 2,0 ^ ^

2 3,3 ^ <</p>

3 3,5 В

4 4,2 В>

5 4.4 ^ ^

6 5.7> ^

7 5.9 <^ </p>

enter image description here

Это как данные отходят от предыдущей строки.

1 Ответ

1 голос
/ 31 марта 2020
while ((pos = list.find(delimiter) != string::npos))

У вас круглые скобки не в том месте, то есть то, что у вас есть, эквивалентно:

while ((pos = (list.find(delimiter) != string::npos) ))
//            (compare first-----------------------)
//     (then assign----------------------------------)

С точки зрения приоритета оператора, присваивание равно way down список, длинный после сравнений.

Так что pos всегда будет либо нулем (если вы не найдете пробел), либо единицей (если вы его найдете). никогда не будет равно позиции этого пробела в строке, за исключением патологического случая, когда пробел является вторым символом.

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

эту строку должно быть:

while ((pos = list.find(delimiter)) != string::npos)
//     (assign first--------------)
//     (then compare-------------------------------)

С полной программой и указанным выше исправлением:

#include <iostream>
#include <queue>

using namespace std;

queue<string> getStringList(string list, string delimiter) {
    queue<string> values;
    size_t pos = 0;
    string token;
    while ((pos = list.find(delimiter)) != string::npos) {
        token = list.substr(0, pos);
        std::cout << token << std::endl;
        values.push(token);
        list.erase(0, pos + delimiter.length());
    }
    values.push(list);
    std::cout << list << endl;
    return values;
}

int main () {
    string x = "0 1.1 ^ ^";
    string delim = " ";

    auto y = getStringList(x, delim);
    return 0;
}

Вы видите, что вывод теперь корректен:

0
1.1
^
^

И, согласно комментарию Реми Лебо, вы печатаете последний элемент, но не добавляете его в список. Поэтому я добавил строку, которая добавляет последний токен в список токенов.

Еще одна вещь, на которую следует обратить внимание. Хотя это хорошо работает с разделителями из одного пробела, проблемы с несколькими пробелами могут вызвать проблемы. Если это становится проблемой, вам может понадобиться более «пуленепробиваемый» токенизатор.

...