1
votes

Analyse d'une chaîne dans un tableau pour C ++

Comment analyser une chaîne dans un tableau en C ++?

Par exemple: "[1: 2: 3: 4] cd / dvd PLDS DVD-RW DU8A6SH DU53 / dev / sr0" code>

Je veux obtenir un tableau d'entiers entre les crochets [] . Donc le tableau contient {1, 2, 3, 4} .

Voici le code que j'ai écrit, mais je ne suis pas sûr que ce soit la manière la plus efficace de l'aborder .

std::string test = "[1:2:3:4]cd/dvd  PLDS  DVD-RW DU8A6SH DU53  /dev/sr0";
int begin = test.find("[");
begin = begin + 1;
std::string sub = test.substr(begin,7);
std::replace(sub.begin(), sub.end(), ':', ' ');

std::vector<int> arr;
std::stringstream ss(sub);
int temp;
while (ss >> temp)
     arr.push_back(temp);

Remarque: quelque chose ne sera pas avant "[" . "[" sera toujours présent. Les nombres seront toujours un chiffre chacun. Il y aura toujours quatre entiers entre les crochets. "]" sera toujours présent. Le texte suit toujours le " " .


6 commentaires

Modifiez votre question et fournissez un énoncé du problème plus détaillé. Quelque chose sera-t-il avant le [? Un [ sera-t-il toujours présent? Les nombres seront-ils toujours 1 caractère? Le séparateur sera-t-il toujours un : ? Un ] sera-t-il toujours présent? Le texte suivra-t-il toujours le ] ?


Le tableau aura un nombre fixe d'éléments, n'est-ce pas? Dans ce cas, vous n'avez même pas besoin / voulez un vecteur d'entiers, mais un std :: array , ou mieux encore - une structure / classe avec des noms de champ significatifs.


Quelque chose ne sera pas avant [. Oui, [sera présent. Oui, les nombres seront toujours à un chiffre. Oui] soyez toujours présent. Le texte suit toujours l'après]


Comme @einpoklum l'a demandé, les nombres seront-ils toujours 4? Voulez-vous vraiment un std::vector ? Peut-être que d'autres choix pourraient être meilleurs. Dans tous les cas, modifiez votre question et ajoutez-y les détails supplémentaires, ne laissez pas les détails sur les commentaires.


Oui. Il y aura quatre nombres entre crochets. Je vais modifier ma question. Merci @Costantino Grana


Vérifiez les réponses et si l'une d'elles convient, marquez-la comme acceptée.


3 Réponses :


-1
votes
int main()
{
    std::string str = "[1:2:3:4]aaa";
    std::vector<int> str_chars = {};

    for (unsigned int i = 0; i < str.size(); ++i)
    {
        char curr = str.at(i);
        if (str.at(i) == '[')
        {
            str_chars.push_back((str.at(i + 1) - '0'));
        }
        else if ((str.at(i) == ':'))
        {
            str_chars.push_back(str.at(i + 1) - '0');
        }
    }

    for (int i = 0; i < str_chars.size(); ++i)
    {
        printf("%d ", str_chars.at(i));
    }

    getchar();
    return 0;
}

7 commentaires

Y aurait-il un problème si je change le vecteur en vecteur ?


vous devez faire ce qui suit pour convertir les caractères en entiers: char c = '1'; int c2 = c - '0'


d'accord, j'ai édité le code pour vous donner les entiers au lieu des caractères


L'utilisation répétée de str.at (...) est excessive, utilisez plutôt str [...] . De plus, str.at (i + 1) lèvera une exception si i est au dernier caractère de la chaîne, car la boucle ne s'arrête pas lorsqu'elle atteint ]


En effet, je l'ai juste fouetté en 1 minute. Je crois aussi que la vérification des bornes est effectuée, donc je l’utilise plus fréquemment moi-même, mais [] fonctionne aussi


@Hjkl Oui, at () vérifie les limites, mais cela est déjà géré par la boucle for , donc at () est juste gaspillé aérien.


Je veillerai à dire à OP de changer le .at (i + 1) en [i + 1] lorsque je le verrai à la prochaine réunion anonyme d'alcooliques



0
votes

Compte tenu des contraintes que vous avez ajoutées, vous pouvez essayer ceci:

    std::array<int, 4> v;
    char c;
    std::stringstream ss(test);
    ss >> c >> v[0] >> c >> v[1] >> c >> v[2] >> c >> v[3] >> c;

Bien sûr, la partie importante est celle que j'ai mise dans l'instruction de bloc, pour la mettre en évidence. Cela vous permet également de vérifier si les personnages sont ce qu'ils sont censés être. Sinon, si vous êtes sûr à 100% que le format sera correct, il peut être simplifié en

    std::vector<int> v(4);
    char c;
    std::stringstream ss(test);
    ss >> c >> v[0] >> c >> v[1] >> c >> v[2] >> c >> v[3] >> c;

Vous pouvez également envelopper cela dans une boucle for, mais s'il s'agit toujours de 4 éléments, pourquoi s'embêter?

Bien sûr, dans ce cas, un std::array peut être utilisé:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>

int main() {
    std::string test = "[1:2:3:4]cd/dvd  PLDS  DVD-RW DU8A6SH DU53  /dev/sr0";

    std::vector<int> v(4);
    {
        char open_square_bracket, colon1, colon2, colon3, close_square_bracket;
        std::stringstream ss(test);
        ss >> open_square_bracket >> v[0] >> colon1 >> v[1] >> colon2 >> v[2] >> colon3 >> v[3] >> close_square_bracket;
    }

    copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, ", "));
    std::cout << "\n";

    return 0;
}

Exécuter sur ideone .


6 commentaires

Merci beaucoup @Costantino Grana! Je suis nouveau en C ++ et je souhaite en savoir plus sur le stringstream. Le flux de chaînes sait-il que les caractères open_square_bracket, ... sont '[', ':' et ']'? De plus, y a-t-il une raison pour laquelle vous avez {} sous std :: vector v (4)?


Non, comme je l'ai écrit plus tard, c'était juste pour le cas où vous vouliez vérifier si open_square_bracket == '[' , puis si colon1 == ':' et ainsi de suite . Les { et } n'étaient là que pour mettre en évidence la partie qui vous intéresse et pour éviter de laisser vivre les variables c et ss plus longtemps que nécessaire.


@ Br0sk1 " Est-ce que le flux de chaînes sait que les caractères open_square_bracket, ... sont '[', ':' et ']'? " - non, ce n'est pas le cas. Seulement que vous lui avez demandé de lire un char pour qu'il le fasse, puis de lire un int pour qu'il le fasse, puis de lire un char pour qu'il le fasse, etc. C'est à vous de valider que chaque char lu est ce que vous attendez de lui.


De plus, toutes les versions de std :: istream lisent des entiers jusqu'au caractère suivant qui ne peuvent pas faire partie d'un entier (espaces, lettres ou ponctuation). Ainsi, lorsqu'ils atteignent un : , ils s'arrêteront. Ainsi, le >> c suivant extrait le caractère : .


@CostantinoGrana Merci! J'ai beaucoup appris de cette conversation!


Utilisez un std :: array s'il vous plaît.



0
votes

Puisque vous codez en dur la taille de substr () , cela implique que les nombres ont des positions et des largeurs fixes, auquel cas vous pouvez simplement utiliser ceci à la place:

std::string test = "[1:2:3:4]cd/dvd  PLDS  DVD-RW DU8A6SH DU53  /dev/sr0";
std::string_view sv(test.data(), test.size());

std::string_view::size_type begin = sv.find('[') + 1;
std::string_view::size_type end = sv.find(']', begin);
std::string_view sub = sv.substr(begin, end - begin);

std::vector<int> arr;
const char *pBegin = sub.data(), *pEnd = pBegin + sub.size();
int temp;

while (pBegin < pEnd)
{
    auto [ptr, ec] = std::from_chars(pBegin, pEnd, temp);
    if (ec != std::errc()) break;
    arr.push_back(temp);
    pBegin = ptr + 1;
}


3 commentaires

Pour la deuxième option que vous avez écrite, pourquoi n'avez-vous pas besoin de ce "std :: replace (sub.begin (), sub.end (), ':', '')"? Ou l'istringstream obtient-il simplement l'entier d'une manière ou d'une autre? Je suis nouveau dans ce domaine, donc toute aide serait bien.


@ Br0sk1 Parce que operator>> arrête la lecture lorsqu'il atteint un caractère qui n'appartient pas au type en cours de lecture. Cela inclut les espaces. Dans mon exemple, operator>> arrêtera la lecture lorsqu'il atteindra un caractère : , ou la fin de la chaîne. L'appel suivant à iss.ignore () utilisé pour ignorer ce caractère : avant que operator>> ne soit appelé à nouveau.


Cela a tellement plus de sens maintenant! Merci beaucoup