J'ai du texte (texte explicite ou expression arithmétique) et je souhaite le scinder en mots.
Si j'avais un seul délimiteur, j'utiliserais:
std::stringstream stringStream(inputString);
std::string Word;
while(std::getline(stringStream, Word, delimiter))
{
wordVector.Push_back(Word);
}
Comment puis-je briser la chaîne en jetons avec plusieurs délimiteurs?
En supposant que l’un des délimiteurs soit newline, ce qui suit lit la ligne et la scinde par la suite. Pour cet exemple, j'ai choisi les délimiteurs espace, apostrophe et point-virgule.
std::stringstream stringStream(inputString);
std::string line;
while(std::getline(stringStream, line))
{
std::size_t prev = 0, pos;
while ((pos = line.find_first_of(" ';", prev)) != std::string::npos)
{
if (pos > prev)
wordVector.Push_back(line.substr(prev, pos-prev));
prev = pos+1;
}
if (prev < line.length())
wordVector.Push_back(line.substr(prev, std::string::npos));
}
Si vous avez un boost, vous pouvez utiliser:
#include <boost/algorithm/string.hpp>
std::string inputString("One!Two,Three:Four");
std::string delimiters("|,:");
std::vector<std::string> parts;
boost::split(parts, inputString, boost::is_any_of(delimiters));
Je ne sais pas pourquoi personne n'a signalé le mode manuel, mais le voici:
const std::string delims(";,:. \n\t");
inline bool isDelim(char c) {
for (int i = 0; i < delims.size(); ++i)
if (delims[i] == c)
return true;
return false;
}
et en fonction:
std::stringstream stringStream(inputString);
std::string Word; char c;
while (stringStream) {
Word.clear();
// Read Word
while (!isDelim((c = stringStream.get())))
Word.Push_back(c);
if (c != EOF)
stringStream.unget();
wordVector.Push_back(Word);
// Read delims
while (isDelim((c = stringStream.get())));
if (c != EOF)
stringStream.unget();
}
De cette façon, vous pouvez faire quelque chose d'utile avec les delims si vous voulez.
Si vous souhaitez savoir comment le faire vous-même et ne pas utiliser de boost.
En supposant que la chaîne de délimiteur puisse être très longue - disons M, vérifier pour chaque caractère de votre chaîne s’il s’agit d’un délimiteur, coûterait O(M) chacun. chaîne, disons en longueur N, est O (M * N).
Je voudrais utiliser un dictionnaire (comme une carte - "délimiteur" à "booléens" - mais ici, je voudrais utiliser un tableau booléen simple qui a la valeur true dans index = valeur ascii pour chaque délimiteur).
À présent, itérer sur la chaîne et vérifier si le caractère est un délimiteur est O (1), ce qui nous donne finalement O(N).
Voici mon exemple de code:
const int dictSize = 256;
vector<string> tokenizeMyString(const string &s, const string &del)
{
static bool dict[dictSize] = { false};
vector<string> res;
for (int i = 0; i < del.size(); ++i) {
dict[del[i]] = true;
}
string token("");
for (auto &i : s) {
if (dict[i]) {
if (!token.empty()) {
res.Push_back(token);
token.clear();
}
}
else {
token += i;
}
}
if (!token.empty()) {
res.Push_back(token);
}
return res;
}
int main()
{
string delString = "MyDog:Odie, MyCat:Garfield MyNumber:1001001";
//the delimiters are " " (space) and "," (comma)
vector<string> res = tokenizeMyString(delString, " ,");
for (auto &i : res) {
cout << "token: " << i << endl;
}
return 0;
}
Remarque: tokenizeMyString renvoie le vecteur par valeur et le crée d'abord sur la pile. Nous utilisons donc ici la puissance du compilateur >>> RVO - optimisation de la valeur renvoyée :)