2012-01-30 198 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