web-dev-qa-db-fra.com

Comment utiliser boost split pour scinder une chaîne et ignorer les valeurs vides?

J'utilise boost :: split pour analyser un fichier de données. Le fichier de données contient des lignes telles que les suivantes.

data.txt

1:1~15  ASTKGPSVFPLAPSS SVFPLAPSS   -12.6   98.3    

Les espaces entre les éléments sont des onglets. Le code que je dois diviser la ligne ci-dessus est la suivante.

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;

Pour la ligne de code ci-dessus, je devrais obtenir une impression sur 5, mais j'en ai 6. J'ai essayé de lire la documentation et cette solution semble devoir faire ce que je veux, il est clair qu'il me manque quelque chose. Merci!

Edit: En exécutant un forloop comme suit sur dataLine, vous obtenez ce qui suit.

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

****
17
PhiloEpisteme

Même si "les séparateurs adjacents sont fusionnés", il semble que les délimètres de fin posent le problème, car même lorsqu'ils sont traités comme un seul séparateur, il reste est un délimiteur.

Votre problème ne peut donc pas être résolu avec split() seul. Mais heureusement, Boost String Algo a trim() ET trim_if() , qui supprime les espaces ou les délimètres du début et de la fin d’une chaîne. Alors appelez simplement trim() sur buf, comme ceci:

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;

Cette question a déjà été posée: boost :: split laisse des jetons vides au début et à la fin de la chaîne - ce comportement est-il souhaité?

16
Oberon

Je recommanderais d'utiliser C++ String Toolkit Library . Cette bibliothèque est beaucoup plus rapide que Boost à mon avis. J'avais l'habitude d'utiliser Boost pour scinder (alias tokenize) une ligne de texte, mais cette bibliothèque était beaucoup plus conforme à ce que je voulais.

L'un des points forts de strtk::parse est sa conversion des jetons en valeur finale et la vérification du nombre d'éléments.

vous pouvez l'utiliser comme suit:

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

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

--- une autre version

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
}

Documentation en ligne pour la bibliothèque: String Tokenizer Documentation Lien vers le code source: C++ String Toolkit Library

7
DannyK

Les espaces blancs de début et de fin sont laissés intentionnellement par boost::split car ils ne savent pas s’ils sont significatifs ou non. La solution consiste à utiliser boost::trim avant d'appeler boost::split.

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

....

boost::trim(buf);
1
Jesse Good