2016-07-30 1 views
2

Ce que je veux:Fractionnement Chaîne en C++

Pour analyser une chaîne d'adresse MAC et obtenir un tableau de six valeurs uint8_t, ayant une entrée comme string str = "01:23:45:AB:CD:EF";.

Ce que j'ai essayé (et n'a pas fonctionné):

sscanf(str.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); 

Pourquoi cela n'a pas fonctionné: Je suis la programmation d'un module Wi-Fi ESP8266 avec l'aide du IDE Arduino. Même si les cœurs officiels de la carte Arduino prennent en charge sscanf(), les cœurs de l'ESP8266 ne le sont pas. (The solution to the issue given on GitHub ne fonctionne pas, comme l'a déclaré nicjohnston.)

moins préféré:

Tout ce qui utilise trop de RAM, les cycles de CPU ou de stockage du programme.
Également certaines choses utilisant ou directement/indirectement selon sscanf, setjmp, longjmp, (et plusieurs autres) peuvent ne pas fonctionner.

Editer: La réponse de @ m.s. ci-dessous est tout à fait correct, mais je me suis rendu compte qu'après avoir conçu mon propre code (donné ci-dessous).

for(uint8_t i=0; i<5; i++) 
    mac[i]=strtol(Serial.readStringUntil(':').c_str(),NULL,16); 
mac[6]=strtol(Serial.readStringUntil('\n').c_str(),NULL,16); 

Répondre

1

Dans votre cas d'utilisation spécifique, vous pouvez simplement itérer sur la chaîne et de convertir les sous-chaînes hexagonales à des chiffres comme ceci:

  • chaque sous-chaîne se compose d'exactement deux caractères hexadécimaux; laisser un sous-chaîne est désignée par XY
  • X et Y sont soit à l'intérieur de [0-9] ou dans [A-F]Asignifie10, B signifie 11, etc. (en décimal)
  • la transformation d'une valeur ASCII au numérique la signification de l'un de ces caractères dépend du jeu de caractères à partir duquel un caractère est:

  • si un caractère c provient de [0-9], sa signification décimale est c-'0', c'est-à-diresoustraire le décalage de telle sorte que le mappage suivant applique '0'=>0, '1' => 1, ...

  • si un produit de carbonisation c est de [A-F], le mappage peut être exprimée comme c-'A'+10

  • le numérique, la valeur décimale v de chaque sous-chaîne XY est ensuite calculé comme suit : v=X*16 + Y

  • les sous-chaînes sont séparées par un seul char (ici un :, mais cela n'a pas d'importance)

Le code suivant implémente ces idées:


#include <string> 
#include <cstdlib> 

std::uint8_t getNum(char hexChar) 
{ 
    if(hexChar >= '0' && hexChar <= '9') 
    { 
     return hexChar - '0'; 
    } 
    return (hexChar-'A'+10); 
} 

int main() 
{ 
    std::uint8_t mac[6]; 
    std::string str = "01:23:45:AB:CD:EF"; 

    std::uint8_t j = 0; 
    for(std::uint8_t i = 0; i<6; ++i) 
    { 
     mac[i] = getNum(str[j])*16 + getNum(str[j+1]); 
     j+=3; // get to the next substring 
    } 
} 
+0

@ sbrm1 'mac' contiendra' {0x01, 0x23, 0x45, 0xAB, 0xCD, 0xEF} ', dont ** sont ** les valeurs hexadécimales et ** pas ** les valeurs ASCII –

+0

Votre code est correct, merci. Mais quelle est la logique derrière tout cela? (ma contribution était erronée). – sbrm1

+0

@ sbrm1 J'ai mis à jour mon code avec une explication –

2

Vous pouvez utiliser des expressions régulières pour extraire le contenu et le stocker dans le tableau. Puis analyser le tableau pour obtenir les équivalents respectifs uint8_t.

Le regex pourrait ressembler à: [0-9A-F][0-9A-F]

Vous pouvez consulter ce lien de référence pour plus de détails sur regex et comment l'utiliser: http://www.cplusplus.com/reference/regex/regex_search/

En C++, regex_search permet de rechercher le motif regex et peut-être extraire le motif recherché (ou apparié).

+1

Je vais vérifier et vous le faire savoir. Merci! Oh, je pense que '[0-9a-fA-f] [0-9a-fA-f]' inclura également les minuscules. Et apparemment l'expression rationnelle supportera tous les types de délimiteurs. Ai-je raison à ce sujet? – sbrm1

+0

Découvert que Arduino ne supporte pas les regex'es. Vous cherchez une bibliothèque regex. Trouvé un: http://mctrl.ml/HRIRqG – sbrm1

+0

C'était une bonne réponse, mais je ne peux pas l'accepter car je viens de découvrir que la seule bibliothèque regex pour Arduino utilise 'setjmp' /' longjmp' qui ne sont pas tous les deux disponible pour le noyau ESP8266. – sbrm1

0

Je suis trop tard, et la réponse de M.S. est correcte.

Ma réponse est un peu différente car elle utilise le pour calculer l'hexadécimal à partir d'une chaîne de caractères et le pour le rendre plus C++ 11. Bien que je ne sache pas si c'est supporté sur votre module ESP8266 j'espère que cela aide.

#include <string> 
#include <array> 

std::array< uint8_t, 6> MAC_fromStringToArray(const std::string& str) 
{ 
    std::array< uint8_t, 6> ret ; 

    for (auto i = 0; i < 6; i++) 
    { 
     ret[i] = std::stoi(str.substr((i * 3), 2), nullptr, 16); 
    } 

    return ret; 
} 

int main() 
{ 
    std::string str = "01:23:45:AB:CD:EF"; 

    std::array< uint8_t, 6> mac = MAC_fromStringToArray(str); 

    return 0; 
} 

EDIT: comme le ne semble pas être disponible je l'ai changé le tableau traditionnel.

uint8_t * MAC_fromStringToArray(const std::string& str, uint8_t arr[]) 
{ 
    for (int i = 0; i < 6; i++) 
    { 
     arr[i] = std::stoi(str.substr((i * 3), 2), nullptr, 16); 
    } 

    return arr; 
} 

Il doit être appelé différemment:

uint8_t arr[6]; 

MAC_fromStringToArray(str, arr); 

Hope it helps, je crains que, sans accès au même compilateur que vous il est diffcile de résoudre votre situation.

+0

va le tester maintenant – sbrm1

+0

Got ''array' ne nomme pas un type' sur' std :: array < uint8_t, 6> MAC_fromStringToArray (const std :: string & str) '(ligne 4). – sbrm1

+0

C'est étrange, peut-être le #include n'est pas traité de manière appropriée? Avez-vous besoin d'ajouter un drapeau pour C++ 11 comme -std = C++ 11 pour g ++? –