2012-01-30 24 views
8

Gram z programowaniem dla Arduino, ale dzisiaj natknąłem się na problem, którego nie mogę rozwiązać dzięki mojej bardzo ograniczonej znajomości języka C. Oto, jak to działa. Tworzę aplikację komputerową, która wysyła dane szeregowe do arduino (deviceID, command, commandparameters). Ten arduino przekaże to polecenie przez RF do innych arduino. w zależności od identyfikatora urządzenia właściwy arduino wykona polecenie.Podziel ciąg na tablicę ciągów

Aby móc określić identyfikator urządzenia, chcę podzielić ten ciąg na ",". to jest mój problem, wiem, jak to zrobić z łatwością w java (nawet bez użycia standardowej funkcji podziału), jednak w C to zupełnie inna historia.

Czy ktokolwiek z was może mi powiedzieć, jak to działa?

dzięki

/* 
    Serial Event example 

When new serial data arrives, this sketch adds it to a String. 
When a newline is received, the loop prints the string and 
clears it. 

A good test for this is to try it with a GPS receiver 
that sends out NMEA 0183 sentences. 

Created 9 May 2011 
by Tom Igoe 

This example code is in the public domain. 

http://www.arduino.cc/en/Tutorial/SerialEvent 

*/ 

String inputString;   // a string to hold incoming data 
boolean stringComplete = false; // whether the string is complete 
String[] receivedData; 

void setup() { 
    // initialize serial: 
    Serial.begin(9600); 
    // reserve 200 bytes for the inputString: 
    inputString.reserve(200); 
} 

void loop() { 
    // print the string when a newline arrives: 
    if (stringComplete) { 
     Serial.println(inputString); 
     // clear the string: 
     inputString = ""; 
     stringComplete = false; 
    } 
} 

/* 
    SerialEvent occurs whenever a new data comes in the 
hardware serial RX. This routine is run between each 
time loop() runs, so using delay inside loop can delay 
response. Multiple bytes of data may be available. 
*/ 
void serialEvent() { 
    while (Serial.available()) { 
     // get the new byte: 
     char inChar = (char)Serial.read(); 
     if (inChar == '\n') { 
      stringComplete = true; 
     } 
     // add it to the inputString: 
     if(stringComplete == false) { 
      inputString += inChar; 
     } 
     // if the incoming character is a newline, set a flag 
     // so the main loop can do something about it: 
    } 
} 

String[] splitCommand(String text, char splitChar) { 
    int splitCount = countSplitCharacters(text, splitChar); 
    String returnValue[splitCount]; 
    int index = -1; 
    int index2; 

    for(int i = 0; i < splitCount - 1; i++) { 
     index = text.indexOf(splitChar, index + 1); 
     index2 = text.indexOf(splitChar, index + 1); 

     if(index2 < 0) index2 = text.length() - 1; 
     returnValue[i] = text.substring(index, index2); 
    } 

    return returnValue; 
} 

int countSplitCharacters(String text, char splitChar) { 
    int returnValue = 0; 
    int index = -1; 

    while (index > -1) { 
     index = text.indexOf(splitChar, index + 1); 

     if(index > -1) returnValue+=1; 
    } 

    return returnValue; 
} 

zdecydowałem Zamierzam użyć funkcji strtok. Teraz mam inny problem. Błąd stało jest

SerialEvent.cpp: In function 'void splitCommand(String, char)':

SerialEvent:68: error: cannot convert 'String' to 'char*' for argument '1' to 'char* strtok(char*, const char*)'

SerialEvent:68: error: 'null' was not declared in this scope

Code jest jak

String inputString;   // a string to hold incoming data 

void splitCommand(String text, char splitChar) { 
    String temp; 
    int index = -1; 
    int index2; 

    for(temp = strtok(text, splitChar); temp; temp = strtok(null, splitChar)) { 
     Serial.println(temp); 
    } 

    for(int i = 0; i < 3; i++) { 
     Serial.println(command[i]); 
    } 
} 
+1

Spójrz na funkcję 'strtok()'. –

+1

'strtok' jest amortyzowany. zamiast tego użyj 'strsep' zamiast – waspinator

+0

Dla przyszłego odniesienia, AFAIK' strtok() 'jest _nie_nie uznawane za przestarzałe (lub deprecjonowane). Kompilator MS Visual C++ wyróżnia go jako niebezpieczną reklamę i alternatywę, podobnie jak GNU/POSIX (różne alternatywy). Użyte prawidłowo i ze świadomością jego wad, będzie działać zgodnie z przeznaczeniem. – Toby

Odpowiedz

1

do dynamicznej alokacji pamięci, trzeba będzie użyć malloc, tj:

String returnvalue[splitcount]; 
for(int i=0; i< splitcount; i++) 
{ 
    String returnvalue[i] = malloc(maxsizeofstring * sizeof(char)); 
} 

trzeba będzie również maksimum Długość łańcucha.

+1

Niekoniecznie potrzebujesz 'malloc()'. Jeśli ciąg nie zmieni się pomiędzy operacją podziału a transmisją danych, to całkowicie bezpieczne jest utrzymywanie zestawu wskaźników w różnych pozycjach w oryginalnym łańcuchu. Jest także szybszy, zużywa mniej pamięci i pozostawia mniej potencjalnych wycieków pamięci. – japreiss

+0

Tak, to może działać, wystarczy ręcznie śledzić długość/koniec każdego ciągu znaków, aby uniknąć nakładania się, ponieważ na żadnym z nich oprócz ostatniego znaku nie będzie znaku "\ 0". – 3Pi

+0

Dobra uwaga. Domyślam się, że może nie być tego warta. – japreiss

0

Sposób dzielenia łańcucha na podstawie separatora polega na użyciu strtok (lub strtok_r). Zobacz także pytanie: this.

+0

'strtok' jest amortyzowany. użyj 'strsep' zamiast – waspinator

+0

Nieużywane przez kogo? Dziesięć minut googlowania okazało się tylko przestarzałym programem Microsoft Visual Studio C++. OP programuje Arduino, który używa własnej wersji C, więc to, czy dana funkcja jest przestarzała w systemie Windows, jest zupełnie nieistotne. – markgz

0

Myślę, że twój pomysł jest dobrym punktem wyjścia. Oto kod, którego używam (do parsowania żądań HTTP REST REST z osią Ethernet).

Chodzi o to, aby użyć pętli while i lastIndexOf i zapisać ciągi w tablicy (ale można zrobić coś innego).

"Żądanie" to ciąg, który chcesz przetworzyć (dla mnie został nazwany prośbą, ponieważ ... było).

int goOn = 1; 
    int count = -1; 
    int pos1; 
    int pos2 = request.length(); 

    while(goOn == 1) { 
     pos1 = request.lastIndexOf("/", pos2); 
     pos2 = request.lastIndexOf("/", pos1 - 1); 

     if(pos2 <= 0) goOn = 0; 

     String tmp = request.substring(pos2 + 1, pos1); 

     count++; 
     params[count] = tmp; 

     // Serial.println(params[count]); 

     if(goOn != 1) break; 
    } 
    // At the end you can know how many items the array will have: count + 1 ! 

Użyłem tego kodu z powodzeniem, ale ich sprawa jest problemem kodowanie gdy próbuję wydrukować params [x] ... Jestem alos początkujący więc nie opanować znaki vs ciąg. ..

Mam nadzieję, że to pomaga.

28

To stara sprawa, ale stworzyliśmy trochę kawałek kodu, które mogą pomóc:

String getValue(String data, char separator, int index) 
{ 
    int found = 0; 
    int strIndex[] = {0, -1}; 
    int maxIndex = data.length()-1; 

    for(int i=0; i<=maxIndex && found<=index; i++){ 
    if(data.charAt(i)==separator || i==maxIndex){ 
     found++; 
     strIndex[0] = strIndex[1]+1; 
     strIndex[1] = (i == maxIndex) ? i+1 : i; 
    } 
    } 

    return found>index ? data.substring(strIndex[0], strIndex[1]) : ""; 
} 

Funkcja ta zwraca jeden ciąg oddzielone predefiniowanego znaku w danym indeksie. Na przykład:

String split = "hi this is a split test"; 
String word3 = getValue(split, ' ', 2); 
Serial.println(word3); 

Należy wydrukować "jest". Możesz również spróbować z indeksem 0 zwracającym "cześć" lub bezpiecznie próbującym indeks 5 zwracającym "test".

Mam nadzieję, że ta pomoc!

+2

Byłem poszukiwanie godzin, aby znaleźć najprostszy sposób to zrobić ... Twój jest zdecydowanie najłatwiejszy –

+0

Thx! Cieszę się, że pomaga komuś! ;) –

+0

To jest fajna funkcja. Wiele osób prosi o takie rozwiązanie. –

-1
int sa[4], r=0, t=0; 
String oneLine = "aa;bb;cc;dd;"; 

for (int i=0; i < oneLine.length(); i++) 
{ if(oneLine.charAt(i) == ';') 
    { sa[t] = oneLine.substring(r, i); r=(i+1); t++; 
    } 
} 

// sa[0] = aa sa[1] = bb sa[2] = cc sa[3] = dd 
+1

Witamy w SO. Proszę pominąć odpowiedzi tylko w kodzie, podając pewien kontekst i wyjaśnienie. Zobacz http://stackoverflow.com/help/how-to-answer –