Как использовать boost split для разделения строки и игнорировать пустые значения?

Я использую boost:: split для анализа файла данных. Файл данных содержит строки, такие как следующие.

data.txt

1:1~15  ASTKGPSVFPLAPSS SVFPLAPSS   -12.6   98.3    

Пустое пространство между элементами - вкладки. Код, который я должен разбить выше, выглядит следующим образом.

std::string buf;
/*Assign the line from the file to buf*/
std::vector<std::string> dataLine;
boost::split( dataLine, buf , boost::is_any_of("\t "), boost::token_compress_on);       //Split data line
cout << dataLine.size() << endl;

Для вышеприведенной строки кода я должен получить распечатку из 5, но я получаю 6. Я попытался прочитать документацию, и это решение кажется так, как будто оно должно делать то, что я хочу, ясно, что я чего-то не хватает. Спасибо!

Изменить: Запустив forloop следующим образом в dataLine, вы получите следующее.

cout << "****" << endl;
for(int i = 0 ; i < dataLine.size() ; i ++) cout << dataLine[i] << endl;
cout << "****" << endl;


****
1:1~15
ASTKGPSVFPLAPSS
SVFPLAPSS
-12.6
98.3

****

Ответы

Ответ 1

Несмотря на то, что "смежные разделители объединены вместе", похоже, что трейлинг-разделители создают проблему, так как даже когда они рассматриваются как единое целое, это все равно один делиметр.

Таким образом, ваша проблема не может быть решена только с помощью split(). Но, к счастью, Boost String Algo имеет trim() и trim_if(), которые отделяют пробелы или делители от начала и конца строки. Поэтому просто вызовите trim() в buf, например:

std::string buf = "1:1~15  ASTKGPSVFPLAPSS SVFPLAPSS   -12.6   98.3    ";
std::vector<std::string> dataLine;
boost::trim_if(buf, boost::is_any_of("\t ")); // could also use plain boost::trim
boost::split(dataLine, buf, boost::is_any_of("\t "), boost::token_compress_on);
std::cout << out.size() << std::endl;

Этот вопрос уже задан: boost:: split left empty tokens в начале и в конце строки - это желаемое поведение?

Ответ 2

Я бы рекомендовал использовать С++ String Toolkit Library. По-моему, эта библиотека намного быстрее, чем Boost. Раньше я использовал Boost для разделения (aka tokenize) строки текста, но обнаружил, что эта библиотека намного больше соответствует тому, что я хочу.

Одна из замечательных особенностей strtk::parse - это преобразование токенов в их конечное значение и проверка количества элементов.

вы можете использовать его так:

std::vector<std::string> tokens;

// multiple delimiters should be treated as one
if( !strtk::parse( dataLine, "\t", tokens ) )
{
    std::cout << "failed" << std::endl;
}

--- другая версия

std::string token1;
std::string token2;
std::string token3:
float value1;
float value2;

if( !strtk::parse( dataLine, "\t", token1, token2, token3, value1, value2) )
{
     std::cout << "failed" << std::endl;
     // fails if the number of elements is not what you want
}

Онлайн-документация для библиотеки: Документация по токенизатору строк Ссылка на исходный код: Библиотека инструментов С++ String Toolkit

Ответ 3

Ведущее и конечное пробелы намеренно оставляются в одиночестве boost::split, потому что оно не знает, значимо ли оно или нет. Решением является использование boost::trim перед вызовом boost::split.

#include <boost/algorithm/string/trim.hpp>

....

boost::trim(buf);