Splittare una String alfanumerica ed inserire valori in char*

Ciao a tutti,
In sintesi devo dividere una stringa (String con la S maiuscola purtroppo) che proviene dal web ed inserirne i valori in determinate variabili char*.
Ma questa soluzione mi dà errore e non riesco a risolverla.
Non sono molto esperto comunque ho cercato di provare.
Tra parentesi chiedo: Ho solo questa String da leggere e dividere, creerà problemi di stabilità col tempo?
Ciao e grazie in anticipo.

char* data1, data2, data3;
String data_web = "aaa\nbbbccc\n33\n\0";

void setup() {
  Serial.begin(115200);
}

void loop() {

  if (data_web.length() > 0) {
    int m = 0;
    int n = data_web.indexOf("\n");
    int indice = 0;
    while (n > 0) {
      String token = data_web.substring(n, m);
      m = n + 1;
      n = data_web.indexOf("\n", n + 1);

      processToken(indice, token);
      indice++;
    }
    converted();
  }
}

void processToken(int i, String str) {
  switch (i) {
    case 0:
      data1 = str.toCharArray();
      break;
    case 1:
      data2 = str.toCharArray();
      break;
    case 2:
      data3 = str.toInt();
      break;
    
    case 3:
      data_web = str;
      break;
  }
}

void converted() {
  Serial.println(data_web);
  Serial.print(F("Data 1 "));
  Serial.println(data1);
  Serial.print(F("Data 2 "));
  Serial.println(data2);
  Serial.print(F("Data 3 "));
  Serial.println(data3);
}

Cerchiamo di capirci
Tu hai una String
Che contiene 4 campi
Separati da new line
Di questi 3 sono alfanumerici e andranno scritti in tre stringhe separate
E uno numerico intero e va scritto innuna variabile int

Come ha citato (a sproposito) uno proprio oggi se vuoi aiutarci ad aiutarti devi descrivere il problema, non la soluzione che pensi

La nostra qui, è una descrizione accettabile del problema?

Questi sono dei puntatori e non puoi fare questa cosa:

cosa che tra l'altro in modo sbagliato..

int len = 10; // considera il carattere `\0` terminatore di stringhe nel valutare la lunghezza
char buf[len];
myString.toCharArray(buf, len);

In sintesi devo dividere una stringa (String con la S maiuscola purtroppo) che proviene dal web ed inserirne i valori in determinate variabili char*.
Ma questa soluzione mi dà errore e non riesco a risolverla.

quindi solo stringhe di C, non variabili intere?

nulla di difficile, sai quanti sono i campi e la loro dimensione massima
questa informazione è necessaria per poter allocare le stringhe

I campi per ora sono solo 3 ma devo poi adattarli per includerne altri.
Essi possono contenere dati numerici o alfanumerici, per ora li considero solo alfanumerici al limite posso convertirli in numero in seguito.
La dimensione massima purtroppo è variabile.

La stringa che ricevo è composta solo da tre campi per ora ed è simile a questa:
String data_web = "aaa\nbbbccc\n33\n\0";

Potrei togliere l'ultimo ritorno a capo.

String data_web = "aaa\nbbbccc\n33\0";

Io devo mettere:
aaa - dentro una variabile
bbbccc - dentro un'altra
33 - dentro un'altra (anche come solo testo).

Potrei assegnare la dimensione massima a 300.

Ripeto non sono esperto in C, ma il mio italiano mi sembrava chiaro.

E purtroppo allora il problema non è risolhibile

Chiaro?

Non hai nemmeno descritto il problema e ti sembrava chiaro?

Hai solo mostrato la tua erronea soluzione e lo consideri chiaro?

Chiaro è "almeno" spiegare il problema, cosa che hai fatto "dopo" di noi

Mettiamo fin da subito i puntini sugli i

Che sia ben chiaro che noi siamo pronti ad aiutare, ma non ad essere pigliati per...

Credi di averlo già detto anche a tuo frtatello e lo ripeto anche a te ... NON tollero questo vostro modo di porvi rispetto agli utenti, quindi ...

... se le informazioni che l'uente da non sono chiare, sono scarse, sono confuse, sono errate, ecc. ecc. NON rispondete ed ignorate il thread ... la stessa cosa vale anche per quanto sta succedendo nell'altra discussione.

Detto questo, alla prossima il BAN è assicurato.

Guglielmo

1 Like

Il problema era già stato descritto all’inizio. Bastava leggere bene prima.
Comunque non voglio entrare in polemica.
Ho insegnato per 43 anni e certe affermazioni non le accetto.
Grazie a chi mi voglia aiutare in seguito.

Grazie stavo già per chiederle il suo intervento. Come ho detto ho insegnato per 43 anni e quando i miei ragazzi mi chiedevano aiuto spiegavo e rispiegavo alla nausea fino a che i loro problemi fossero risolti.
Manca l'educazione oggigiorno e questo mi preoccupa profondamente per il futuro.

2 Likes

Eh... A scuola non possono insegnarla, perché se un insegnante punisce un "povero" ragazzo poi è accusato lui; anche se della gente picchia una persona che ha scippato una persona anziana, poi la polizia va a cercare "gli aggressori"... :disappointed_relieved:

Poi... In fatto di array di caratteri io sono uno degli ultimi, ma... "La stringa che viene dal web" è un film di fantascienza/horror?... :smile:
Voglio dire: da ciò che arriva dal web non si può fare direttamente un array di caratteri non String?...

Buongiorno,
Non mi faccio vivo da un po', ma ho avuto da studiare altro.
Il problema mi sembra di averlo abbastanza capito da poter dire un paio di cose, che purtroppo per l'autore non sono positive.
Purtroppo la dimensione massima, il tipo, e il numero di elementi deve essere noto. Ovviamente queste caratteristiche possono eventualmente cambiare elemento per elemento, e la dimensione massima non significa doverli usare tutti. Comunque questi mi sembrano i requisiti minimi per programmare in C (e mi viene da dire anche per sapere che cosa si sta facendo).
Ti direi di tornare qui, una volta che avrai definito queste cose.

1 Like

Se la dimensione massima delle stringhe è variabile hai solo 2 opzioni praticabili secondo me:

  • lavorare con le stringhe classiche C (array di char) e prevedere una massima lunghezza che contempli anche il caso peggiore
  • lavorare con le String di Arduino che possono essere riallocate dinamicamente quando serve e se hai bisogno di usare in qualche funzione il char* o il const char*, chiamare la funzione myString.c_str();

Direi che la prima opzione è la migliore ed evita l'uso della classe String ...

... crea un bel char array della lunghezza massima, usa le varie funzioni che trova in <string.h> per fare il parsing e separare gli elementi ed ha risolto :wink:

Guglielmo

Per ora grazie delle vostre indicazioni, cerco di realizzare qualche cosa poi vi faccio sapere.

Per adesso il post di @cotestatnt sembra quello che sintetizza meglio il problema e le possibili soluzioni.

Però viene da chiedersi:

  1. Il contenuto della stringa che viene dal web è modificabile?
  2. Cosa ci devi fare con i puntatori ai vari token?

Anche la classe String può essere configurata per avere un buffer di dimensioni prestabilite.

In base alla scheda arduino si può decidere anche di allocare il buffer locale dentro una funzione, cioè allocato nello stack, quindi 300 byte nello stack più altri 100 di riserva potrebbe essere abbastanza sicuro e non sprecare RAM statica.

Se la risposta al punto 1 è : si è modificabile, potrei pensare ad associare alla stringa un header che descrive il numero di campi e l'indice di inizio di ognuno. Allora posso allocare staticamente un buffer di dimensione atta a contenere un campo.

"aaa\nbbbccc\n33\n\0"

Questo è facile trasformarlo in "aaa0" e restituire il puntatore, ad una seconda chiamata il puntatore punta a "bbbbccc0" ecc. In sostanza trasformo la stringa in tante stringhe terminate con null.

Devo scappare.

Io andrei oltre.. se sono dati che vengono dal web, allora si tratta al 99% di uno Stream (come ad esempio un web client) e userei direttamente quello senza passare per una variabile di "accumulo" di tipo String facendo dei semplici

client.readStringUntil('\n');
per ogni token.

Premessa d’obbligo viste le mie limitatissime conoscenze del benamato non per me, ma naturalmente per voi: C o C++.

Quando ho un grande problema in corso cerco di dividerlo e risolverlo in sotto-problemi.

È per questo che sono partito nel descrivere all’inizio del mio topic solo la parte String.

A cosa mi serve tutto questo.

Sul -mio sito web- ho creato una pagina in html e php con lo scopo di poter comandare determinate cose.

Esse devono essere disponibili a me o ad altri usando una semplice connessione a internet e, non meno importante, poterlo fare da qualsiasi parte del globo.

Faccio alcuni esempi banali:

  • accendere le luci di casa

  • attivare un condizionatore o una caldaia

  • avvisare con una matrice LED che i campi in terra rossa non sono praticabili per la pioggia (es. tennis)

  • avvisare con una matrice LED gli orari di apertura di un negozio

  • aiutare con una matrice LED una persona disabile

  • attivare il sistema di irrigazione

  • avvisare con una matrice LED il pranzo è già pronto in frigorifero devi solo scaldarlo

  • ecc.

Banale? Credo proprio di no. Il mio progetto deve servire a più necessità.

Per cui avevo contemplato:

  • scritte variabili

  • scritte fisse

  • possibilità di accendere e spegnere accessori vari.

Qualcuno direbbe:

  • Perché non hai fatto tutto su arduino o ESP compreso l’html e il php?

Rispondo semplicemente perché mi sono imbattuto in diversi ostacoli per poter trasformare una gestione local in global di un sever o client che sia (vedi Ngrok ecc. gestione del modem ecc.)

Ho un sito mio e lo gestisco a mio piacimento e, importante, è in rete disponibile ovunque io sia.

Espongo dall’inizio. Sono partito da qui per ricevere i dati dal web:

void getdata_web() {
  if (wifiMulti.run() == WL_CONNECTED) {
    HTTPClient http;
    http.begin("http://esempio.xy/data.txt");
    int httpCode = http.GET();
    // Serial.println();
    // Serial.print(F("HTTP code: "));
    // Serial.println(httpCode);
    if (httpCode > 0) {
      if (httpCode == HTTP_CODE_OK) {
        String data_web = http.getString();
        Serial.println(data_web);

        char data[data_web.length() + 1];  // +1 for the null terminator

        data_web.toCharArray(data, data_web.length() + 1);

        Serial.println(F("Caratteri"));
        Serial.println(data);  // Display the message on serial monitor

      } else {
        Serial.print(F("HTTP GET: Failed"));
        Serial.println(http.errorToString(httpCode).c_str());
      }
    }
    http.end();
  }
}

Quello di seguito invece è il codice che ho elaborato per estrapolare i dati dal file di testo proveniente da internet salvo modifiche con vostri consigli e/o aiuti.

Chiedo cortesemente a voi se sia possibile migliorare il mio lavoro che credo sia molto elementare.

Le mie conoscenze purtroppo sono arrivate solo fino a questo.

Note aggiuntive:

Ho assegnato a tutti i testi una dimensione massima fissa di 35, per ora, poi deciderò in seguito valori diversi nel definitivo.

Ho deciso di impiegare gli array di char (non so se mi sono espresso bene) ed usare un ciclo for per la loro stampa.

Perché? Ho visto che questo sistema non mi ha creato problemi nella stampa dei testi con le matrici a led 64x64 usati per le insegne luminose.

Gli ultimi valori della stringa mi servono per i toggle switch ON - OFF che attiveranno i livelli logici delle porte di OUTPUT per attivazione di accensioni e spegnimenti vari.

Il sistema che ho usato per trasformare il carattere - 0 - zero che in realtà in ASCII è il 48 in numero reale (cioè 0) è orrendo anche se funziona.

Si tratta di questo: —> data7 = globaldata[a] - 48; <—-

Ditemi come posso fare meglio.

Ho dovuto cambiare il carattere separatore n\ della stringa e passare al - ; - punto e virgola perché mi creava dei crash continui, avrei preferito il ritorno a capo, c'è un modo per farlo?

char data1[35], data2[35], data3[35], data4[35], data5[35], data6[35];
int data7, data8, data9; // da convertire in numero
int dim_File = 0;

String data_web = "a - Testo dimensione variabile 1;b - Testo dimensione variabile 2;c - Testo dimensione variabile 3;Testo 1;Testo 2;Testo 3;1;0;1\0"; // 1;0;1 questi ultimi valori mi servono per i toggle switch ON - OFF

char globaldata[300];

void setup() {
  Serial.begin(115200);
}

void loop() {
  dim_File = data_web.length();

  for (int a = 0; a < dim_File; a++) {
    globaldata[a] = data_web[a];
  }

  Serial.println(F("Stringa "));
  for (int k = 0; k < dim_File; k++) {
    Serial.print(globaldata[k]);
  }
  Serial.println();
  prova_stampa();
  delay(2000);
}

void prova_stampa() {
  int cambio_variabile = 1;
  int b = 0;
  for (int a = 0; a < dim_File; a++) {
    if (globaldata[a] == 59)  // 59 = ; carattere delimitatore
    {
      a = a + 1;
      b = 0;
      cambio_variabile++;
    }

    if (globaldata[a] == NULL)  
    {
      break;
    }
    if (cambio_variabile == 1) {
      data1[b] = globaldata[a];
      b++;
    }
    if (cambio_variabile == 2) {
      data2[b] = globaldata[a];
      b++;
    }
    if (cambio_variabile == 3) {
      data3[b] = globaldata[a];
      b++;
    }
    if (cambio_variabile == 4) {
      data4[b] = globaldata[a];
      b++;
    }
    if (cambio_variabile == 5) {
      data5[b] = globaldata[a];
      b++;
    }
    if (cambio_variabile == 6) {
      data6[b] = globaldata[a];
      b++;
    }
    if (cambio_variabile == 7) {
      data7 = globaldata[a] - 48; // è orrendo come posso fare per trasformare questo carattere in numero?
      b++;
    }
    if (cambio_variabile == 8) {
      data8 = globaldata[a] - 48; // è orrendo come posso fare per trasformare questo carattere in numero?
      b++;
    }
    if (cambio_variabile == 9) {
      data9 = globaldata[a] - 48; // è orrendo come posso fare per trasformare questo carattere in numero?
      b++;
    }
  }
  Serial.print(F("Data 1 "));
  for (int k = 0; k < 35; k++) {
    Serial.print(data1[k]);
  }
  Serial.println();
  Serial.print(F("Data 2 "));
  for (int k = 0; k < 35; k++) {
    Serial.print(data2[k]);
  }
  Serial.println();
  Serial.print(F("Data 3 "));
  for (int k = 0; k < 35; k++) {
    Serial.print(data3[k]);
  }
  Serial.println();
  Serial.print(F("Data 4 "));
  for (int k = 0; k < 35; k++) {
    Serial.print(data4[k]);
  }
  Serial.println();
  Serial.print(F("Data 5 "));
  for (int k = 0; k < 35; k++) {
    Serial.print(data5[k]);
  }
  Serial.println();
  Serial.print(F("Data 6 "));
  for (int k = 0; k < 35; k++) {
    Serial.print(data6[k]);
  }
  Serial.println();
  Serial.print(F("Data 7 "));

  Serial.print(data7);

  Serial.println();
  Serial.print(F("Data 8 "));

  Serial.print(data8);

  Serial.println();
  Serial.print(F("Data 9 "));

  Serial.print(data9);

  Serial.println();
}


In passato mi è stato detto che sono stato poco chiaro, così mi sembra di essere stato prolisso.

Un consiglio a chi aiuta…

Non sempre dietro un nickname c’è già una persona con una certa esperienza che forse ha bisogno solo di quel -quid- (abbastanza insignificante per gli esperti) per finire un progetto.

Il più delle volte (come ad esempio me e tanti altri) c’è un individuo che ha bisogno di qualcosa già fatto che gli servirà per capire il meccanismo, il concetto, il metodo per risolvere una determinata situazione.

Quando avrò completato anche la parte web ci risentiremo.

Buona giornata e grazie come sempre.

Io sinceramente trovo questa scelta poco ragionata:

  • non hai dimestichezza con il C/C++ per tua stessa ammissione e le C string sono notoriamente più ostiche per chi è agli inizi o proviene da altri ambienti;
  • stai usando un microcontrollore che ha SRAM in abbondanza e ti consente di usare serenamente anche gli oggetti più "voluminosi", figuriamoci qualche String...
    Io sono dell'opinione che le basi siano necessarie sempre e quindi conoscere e saper manipolare le C string è un MUST, ma probabilmente era da fare uno step prima e non dopo esserti imbarcato in questo progetto che è abbastanza complesso;
  • stai già usando oggetti String...la libreria HTTPClient in pratica usa solo delle String e mi pare che funzioni egregiamente;
  • se proprio devi, una String la puoi sempre trattare come fosse un array di char come già hai fatto qui per fare questa copia (che io trovo inutile).

Ad ogni modo questo è un esempio dove faccio il tokenizing di una stringa che fa uso solo delle C string con strotk() e le istruzioni di conversione atoi() atof() etc etc