Как использовать 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);