20 votes

Comment utiliser boost split pour diviser une chaîne de caractères 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 blancs entre les éléments sont des onglets. Le code que je dois utiliser pour diviser la ligne ci-dessus est le suivant.

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 de 5, mais j'obtiens 6. J'ai essayé de lire la documentation et cette solution semble faire ce que je veux, mais il y a quelque chose qui m'échappe. Merci de votre compréhension.

Editer : En exécutant une boucle for comme suit sur dataLine, on obtient 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

****

19voto

Oberon Points 1721

Même si "les séparateurs adjacents sont fusionnés", il semble que ce soient les délimiteurs de fin qui posent problème, car même s'ils sont traités comme un seul élément, le problème persiste. est un delimètre.

Votre problème ne peut donc pas être résolu par split() seul. Mais heureusement, Boost String Algo a trim() y trim_if() qui supprime les espaces blancs ou les délimiteurs au début et à la fin d'une chaîne de caractères. Il suffit donc d'appeler 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 tokens vides au début et à la fin de la chaîne - est-ce un comportement souhaité ?

7voto

DannyK Points 419

Je recommande d'utiliser Bibliothèque C++ String Toolkit . Cette bibliothèque est beaucoup plus rapide que Boost à mon avis. J'avais l'habitude d'utiliser Boost pour diviser (aka tokenize) une ligne de texte mais j'ai trouvé que cette bibliothèque correspondait beaucoup mieux à ce que je voulais.

L'un des aspects les plus intéressants de la strtk::parse est la conversion des jetons en leur valeur finale et la vérification du nombre d'éléments.

vous pouvez l'utiliser ainsi :

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 : Documentation sur le tokenizer de chaîne Lien vers le code source : Bibliothèque C++ String Toolkit

1voto

Jesse Good Points 22971

Les espaces blancs de début et de fin sont intentionnellement laissés en l'état par boost::split car il ne sait pas s'il est significatif ou non. La solution consiste à utiliser boost::trim avant d'appeler boost::split .

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

....

boost::trim(buf);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X