web-dev-qa-db-fra.com

c ++ Fractionner une chaîne par un caractère?

Comment fractionner une chaîne telle que "102:330:3133:76531:451:000:12:44412" par le caractère ":" et placer tous les nombres dans un tableau int (la séquence de nombres sera toujours longue de 8) De préférence sans utiliser une bibliothèque externe telle que boost.

Aussi, je me demande comment je peux supprimer les caractères inutiles de la chaîne avant qu'elle ne soit traitée, tels que "$" et "#"?

10
user2705775

stringstream peut faire tout cela.

  1. Fractionner une chaîne et stocker dans int array:

    string str = "102:330:3133:76531:451:000:12:44412";
    std::replace(str.begin(), str.end(), ':', ' ');  // replace ':' by ' '
    
    vector<int> array;
    stringstream ss(str);
    int temp;
    while (ss >> temp)
        array.Push_back(temp); // done! now array={102,330,3133,76531,451,000,12,44412}
    
  2. Supprimez les caractères inutiles de la chaîne avant son traitement, tels que $ et #: exactement comme le traitement de : décrit ci-dessus.

9
herohuyongtao

La méthode standard en C utilise strtok comme d’autres ont répondu. Cependant, strtok ne ressemble pas à C++- et aussi unsafe . La méthode standard en C++ utilise std::istringstream

std::istringstream iss(str);
char c; // dummy character for the colon
int a[8];
iss >> a[0];
for (int i = 1; i < 8; i++)
    iss >> c >> a[i];

Si l'entrée a toujours un nombre fixe de jetons comme celui-ci, sscanf peut être une autre solution simple.

std::sscanf(str, "%d:%d:%d:%d:%d:%d:%d:%d", &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8);
8
phuclv

Je devais écrire du code comme celui-ci auparavant et j'ai trouvé une question sur Stack Overflow pour scinder une chaîne par un délimiteur. Voici la question initiale: link .

Vous pouvez utiliser ceci avec std::stoi pour construire le vecteur.

std::vector<int> split(const std::string &s, char delim) {
    std::vector<int> elems;
    std::stringstream ss(s);
    std::string number;
    while(std::getline(ss, number, delim)) {
        elems.Push_back(std::stoi(number));
    }
    return elems;
}

// use with:
const std::string numbers("102:330:3133:76531:451:000:12:44412");
std::vector<int> numbers = split(numbers, ':');

Voici un exemple de travail idéal .

4
Lander

Voici un moyen… pas le plus malin mais rapide à écrire (8 répétitions sont tout près de garantir une boucle). Cette approche de l'analyse syntaxique est très utile, donc il est bon d'apprendre. !(iss >> c) s'assure qu'il n'y a pas de caractères de fin non blancs dans la chaîne.

std::istringstream iss(the_string);
char c;
int n[8];
if (iss >> n[0] >> c && c == ':' &&
    iss >> n[1] >> c && c == ':' &&
    iss >> n[2] >> c && c == ':' &&
    iss >> n[3] >> c && c == ':' &&
    iss >> n[4] >> c && c == ':' &&
    iss >> n[5] >> c && c == ':' &&
    iss >> n[6] >> c && c == ':' &&
    iss >> n[7] && !(iss >> c))
    ...
1
Tony Delroy

Vous pouvez utiliser strtok() pour scinder votre chaîne, peut-être dans une boucle while.

Lorsque vous obtenez une chaîne individuelle, vous pouvez utiliser atoi(xxx) pour la conversion en ints. 

0
Digital_Reality

Vrai ! il n'y a pas magie elfique

Son un peu répondu ici aussi

#include <cstring>
#include <iostream>
#include<cstdlib>
#include<vector>

int main() 
{
    char input[100] = "102:330:3133:76531:451:000:12:44412";
    char *token = std::strtok(input, ":");
    std::vector<int> v;

    while (token != NULL) {
        v.Push_back( std::strtol( token, NULL, 10 ));
        token = std::strtok(NULL, ":");
    }

    for(std::size_t i =0 ; i < v.size() ; ++i)
        std::cout << v[i] <<std::endl;
}

Démo Ici

0
P0W

Pour supprimer les caractères '#' et '$', vous pouvez utiliser l'algorithme standard std::remove_if. Cependant, tenez compte du fait que s'il existe par exemple la chaîne suivante "12 # 34", après avoir supprimé "#", vous obtiendrez un "1234". Si vous avez besoin que la chaîne obtenue ressemble à "12 34" ou "12:34", alors au lieu de std::remove_if, il est préférable d'utiliser std::replace_if.

Vous trouverez ci-dessous un exemple de code qui effectue la tâche. Vous devez inclure des en-têtes

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>

int main()
{
    char s[] = "102:$$330:#3133:76531:451:000:$12:44412";

    std::cout << s << std::endl;

    char *p = std::remove_if( s, s + std::strlen( s ), 
        []( char c ) { return ( c == '$' || c == '#' ); } );
    *p = '\0';

    std::cout << s << std::endl;

    const size_t N = 8;
    int a[N];

    p = s;
    for ( size_t i = 0; i < N; i++ )
    {
        a[i] = strtol( p, &p, 10 );
        if ( *p == ':' ) ++p;
    }

    for ( int x : a ) std::cout << x << ' ';
    std::cout << std::endl;
}

La sortie est

102:$$330:#3133:76531:451:000:$12:44412
102:330:3133:76531:451:000:12:44412
102 330 3133 76531 451 0 12 44412
0
Vlad from Moscow

comprendre 

#include <string.h>

int main ()
{
  char str[] ="102:330:3133:76531:451:000:12:44412";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str,":");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, ":");
  }
  return 0;
}
0
Imtiaz Emu

Une autre solution utilisant les fonctionnalités d’expression régulière de C++ 11.

#include <algorithm>
#include <iostream>
#include <iterator>
#include <ostream>
#include <regex>
#include <sstream>
#include <string>
#include <vector>

int main()
{
    const std::string s = "102:330:3133:76531:451:000:12:44412";

    // Replace each colon with a single space
    const std::regex pattern(":");
    const std::string r = std::regex_replace(s, pattern, " ");

    std::istringstream ist(r);

    std::vector<int> numbers;
    std::copy(std::istream_iterator<int>(ist), std::istream_iterator<int>(),
        std::back_inserter(numbers));

    // We now have a vector of numbers

    // Print it out
    for (auto n : numbers)
    {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}
0
user515430