Utilisation de strtok avec une chaîne std::string
j'ai une chaîne que je tiens à marquer.
Mais le C strtok()
fonction nécessite à ma chaîne pour être un char*
.
Comment puis-je faire cela simplement?
j'ai essayé:
token = strtok(str.c_str(), " ");
qui échoue parce qu'il le transforme en const char*
, pas char*
10 réponses
#include <iostream>
#include <string>
#include <sstream>
int main(){
std::string myText("some-text-to-tokenize");
std::istringstream iss(myText);
std::string token;
while (std::getline(iss, token, '-'))
{
std::cout << token << std::endl;
}
return 0;
}
Ou, comme mentionné, utilisez le boost pour plus de flexibilité.
Si boost est disponible sur votre système (je pense que c'est standard sur la plupart des distributions Linux de nos jours), il a un Tokenizer classe que vous pouvez utiliser.
si ce N'est pas le cas, alors un petit Google fait un tokenizer roulé à la main pour std:: string que vous pouvez probablement simplement copier et coller. C'est très court.
et, si vous n'aimez pas l'un ou l'autre de ceux-ci, alors voici une fonction split() que j'ai écrite pour faire mon la vie plus facile. Il cassera une corde en morceaux en utilisant n'importe laquelle des pièces de "delim" comme séparateurs. Les pièces sont ajoutées à la "parties" vecteur:
void split(const string& str, const string& delim, vector<string>& parts) { size_t start, end = 0; while (end < str.size()) { start = end; while (start < str.size() && (delim.find(str[start]) != string::npos)) { start++; // skip initial whitespace } end = start; while (end < str.size() && (delim.find(str[end]) == string::npos)) { end++; // skip to end of word } if (end-start != 0) { // just ignore zero-length strings. parts.push_back(string(str, start, end-start)); } } }
Dupliquer la chaîne, marquer, puis gratuit.
char *dup = strdup(str.c_str());
token = strtok(dup, " ");
free(dup);
Il y a une solution plus élégante.
Avec std:: string, vous pouvez utiliser resize() pour allouer un buffer suffisamment grand, et &s[0] pour obtenir un pointeur vers le buffer interne.
à ce point, beaucoup de gens bien vont sauter et crier sur l'écran. Mais c'est la réalité. Il y a environ 2 ans!--2-->
le groupe de travail bibliothèque a décidé (réunion à Lillehammer) que tout comme pour std::vector, std:: string devrait aussi formellement, pas seulement dans la pratique, avoir une garantie mémoire tampon contiguë.
l'autre problème est does strtok() augmente la taille de la chaîne. La documentation du MSDN dit:
Chaque appel à strtok modifie strToken en insérant un caractère nul après le jeton retourné par cet appel.
Mais ce n'est pas correct. En fait la fonction remplace les premier occurrence d'un caractère de séparateur avec \0. Aucun changement dans la taille de la corde. Si on a ça chaîne de caractères:
un-deux-trois-quatre
nous finirons avec
un\0two\0--trois\0-quatre
Donc ma solution est très simple:
std::string str("some-text-to-split");
char seps[] = "-";
char *token;
token = strtok( &str[0], seps );
while( token != NULL )
{
/* Do your thing */
token = strtok( NULL, seps );
}
Lire la discussion sur http://www.archivum.info/comp.lang.c++/2008-05/02889/does_std::string_have_something_like_CString::GetBuffer
EDIT: l'usage de const cast est utilisé pour démontrer l'effet de strtok()
lorsqu'il est appliqué à un pointeur retourné par string::c_str().
Vous ne devrait pas utiliser
strtok()
puisqu'il modifie la chaîne tokenisée qui peut conduire à un comportement indésirable, sinon indéfini, comme la chaîne C "appartient" à l'instance de la chaîne.
#include <string>
#include <iostream>
int main(int ac, char **av)
{
std::string theString("hello world");
std::cout << theString << " - " << theString.size() << std::endl;
//--- this cast *only* to illustrate the effect of strtok() on std::string
char *token = strtok(const_cast<char *>(theString.c_str()), " ");
std::cout << theString << " - " << theString.size() << std::endl;
return 0;
}
Après l'appel à strtok()
, l'espace a été "enlevé" de la chaîne, ou refusé à un non-imprimable caractère, mais la longueur reste inchangée.
>./a.out
hello world - 11
helloworld - 11
vous devez donc recourir au mécanisme natif, à la duplication de la chaîne ou à une bibliothèque tierce comme mentionné précédemment.
je suppose que le langage est C, ou c++...
strtok, IIRC, remplacer les séparateurs par \0. C'est ce qu'il ne peut pas utiliser un const string. Pour contourner ce problème, que "rapidement", si la chaîne n'est pas énorme, vous pouvez simplement strdup (). Ce qui est sage si vous avez besoin de garder la corde non altérée (ce que le const suggère...).
d'un autre côté, vous pourriez vouloir utiliser un autre tokenizer, peut-être roulé à la main, moins violent sur l'argument donné.
en supposant que par "string" vous parlez de std:: string en C++, vous pourriez avoir un regard sur le Tokenizer package Boost.
Il échoue parce que str.c_str()
renvoie la chaîne constante mais char * strtok (char * str, const char * delimiters )
nécessite une chaîne volatile. Si vous avez besoin d'utiliser * const_cast < char > afin de rendre voletile.
Je vous donne un programme complet mais petit pour tokeniser la chaîne en utilisant la fonction C strtok ().
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int main() {
string s="20#6 5, 3";
char *str=const_cast< char *>(s.c_str());
char *tok;
tok=strtok(str, "#, " );
int arr[4], i=0;
while(tok!=NULL){
arr[i++]=stoi(tok);
tok=strtok(NULL, "#, " );
}
for(int i=0; i<4; i++) cout<<arr[i]<<endl;
return 0;
}
tout d'abord, je dirais utiliser tokenizer boost.
Si vos données sont séparées par un espace, alors la bibliothèque string stream est très utile.
Mais les deux ci-dessus ont déjà été abordés.
Ainsi, comme troisième alternative de type C, je propose de copier la chaîne std::Dans un tampon pour modification.
std::string data("The data I want to tokenize");
// Create a buffer of the correct length:
std::vector<char> buffer(data.size()+1);
// copy the string into the buffer
strcpy(&buffer[0],data.c_str());
// Tokenize
strtok(&buffer[0]," ");
si vous ne vous opposez pas à open source, vous pouvez utiliser les classes subbuffer et subparser de https://github.com/EdgeCast/json_parser