2012-01-30 231 views
8

我一直在玩arduino的編程,但今天我遇到了一個問題,我無法用我非常有限的C知識來解決。 這是怎麼回事。 我正在創建一個將串行輸入發送到arduino的pc應用程序(deviceID,command,commandparameters)。這個arduino將通過RF將該命令傳送給其他arduino。取決於deviceID,正確的arduino將執行該命令。將字符串拆分爲字符串數組

爲了能夠確定deviceID我想分割該字符串的「,」。 這是我的問題,我知道如何在java中輕鬆做到這一點(即使不使用標準拆分函數),但在C中它是一個完全不同的故事。

你們任何人都可以告訴我如何使這個工作?

感謝

/* 
    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; 
} 

我已經決定,我將使用strtok功能。 我現在正在遇到另一個問題。發生錯誤是

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

代碼是這樣,

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

看那'的strtok()'函數。 – 2012-01-30 23:26:28

+1

'strtok'折舊。使用'strsep'代替 – waspinator 2013-03-05 18:00:42

+0

爲了將來的參考,AFAIK'strtok()'不被棄用(或折舊)。 MS Visual C++編譯器將其標記爲不安全的廣告提供和替代,正如GNU/POSIX(不同的替代方案)一樣。正確使用和意識到它的缺點,它將按預期運行。 – Toby 2017-03-15 11:56:29

回答

1

對於動態分配的內存,您將需要使用malloc,即:

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

你還需要最大字符串長度。

+1

你不一定需要'malloc()'。如果字符串在拆分操作和數據傳輸之間不會發生變化,那麼將原始字符串中的各個位置指向一組指針是完全安全的。它也更快,使用更少的內存,並留下更少的潛在內存泄漏。 – japreiss 2012-01-31 00:10:50

+0

是的,這可以工作,你只需要保持手動跟蹤每個字符串的長度/結尾以避免重疊,因爲除了最後一個以外,任何字符都不會有''\ 0''終止字符。 – 3Pi 2012-01-31 00:26:30

+0

好點。猜猜這可能不值得。 – japreiss 2012-01-31 00:48:05

0

C基於分隔符分割字符串的方法是使用strtok(或strtok_r)。 另請參閱this的問題。

+0

'strtok'折舊。使用'strsep'而不是 – waspinator 2013-03-05 17:59:55

+0

棄用誰?十分鐘的谷歌搜索只會在Microsoft Visual Studio C++中引起棄用。 OP是編程一個Arduino,它使用它自己的C版本,所以在Windows中是否棄用函數是完全不相關的。 – markgz 2013-03-06 07:13:43

0

我認爲你的想法是一個很好的起點。這是我使用的代碼(用以太網盾解析HTTP GET REST請求)。

想法是使用while循環和lastIndexOf並將字符串存儲到數組中(但是您可以執行其他操作)。

「請求」是你想要解析的字符串(對我來說它被稱爲請求,因爲它是)。

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 ! 

我已經成功地使用這種代碼,但我的事情時,我嘗試打印PARAMS [X]他們是一個編碼的問題...我是阿洛斯一個初學者,所以我不掌握字符VS字符串。 ..

希望它有幫助。

28

這是一個老問題,但我已經建立一些一段代碼,可能有幫助:

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]) : ""; 
} 

此函數返回一個給定索引處由預定字符分隔單個字符串。例如:

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

應打印'是'。您也可以嘗試索引0返回「hi」或安全嘗試索引5返回「測試」。

希望得到這個幫助!

+2

我一直在尋找幾小時找到最簡單的方法來做到這一點......你的是迄今爲止最簡單的 – 2013-03-15 19:49:15

+0

Thx!我很高興它可以幫助別人! ;) – 2013-03-18 23:52:54

+0

這是一個很好的功能。有很多人要求這樣的解決方案。 – 2015-02-12 18:17:36

-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

歡迎來到SO。請通過提供一些背景和解釋來省略代碼。請參閱http://stackoverflow.com/help/how-to-answer – 2017-03-15 10:33:45