【问题标题】:Split String into String array将字符串拆分为字符串数组
【发布时间】:2012-02-22 17:54:00
【问题描述】:

我一直在为 arduino 进行编程,但今天我遇到了一个我无法用我非常有限的 C 知识解决的问题。 事情是这样的。 我正在创建一个将串行输入发送到 arduino(设备 ID、命令、命令参数)的 pc 应用程序。该arduino将通过RF将该命令传输到其他arduino。根据 deviceID,正确的 arduino 将执行命令。

为了能够确定我想在“,”上拆分该字符串的设备ID。 这是我的问题,我知道如何在 java 中轻松做到这一点(即使不使用标准的 split 函数),但是在 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:在函数'void splitCommand(String, char)'中:

SerialEvent:68: 错误:无法将参数 '1' 的 'String' 转换为 'char*' 到 'char* strtok(c​​har*, const char*)'

SerialEvent:68: 错误:'null' 未在此范围内声明

代码就像,

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

【问题讨论】:

  • strtok()函数。
  • strtok 已折旧。改用strsep
  • 为了将来参考,AFAIK strtok()弃用(或折旧)。 MS Visual C++ 编译器将其标记为不安全的广告提供和替代方案,GNU/POSIX 也是如此(尽管有不同的替代方案)。正确使用并意识到其缺点,它将按预期运行。
  • strtok 不是解决此问题的好方法:它会将, 的任何序列视为单个分隔符。此外,它可能在 arduino 平台上不可用。

标签: c arrays string arduino


【解决方案1】:

这是一个老问题,但我创建了一些可能有帮助的代码:

 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);

应该打印'is'。您也可以尝试使用返回“hi”的索引 0 或安全地尝试返回“测试”的索引 5。

希望对您有所帮助!

【讨论】:

  • 这很棒。谢谢。只是一个警告,它只分割一个字符。我使用带有~ 的字符串来拆分项目,并使用~~ 来换行,但它不起作用。
  • 请把啤酒寄到哪里!很好的解决方案,完美运行
【解决方案2】:

实施:

int sa[4], r=0, t=0;
String oneLine = "123;456;789;999;";

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

结果:

    // sa[0] = 123  
    // sa[1] = 456  
    // sa[2] = 789  
    // sa[3] = 999

【讨论】:

  • 欢迎来到 SO。请通过提供一些上下文和解释省略仅代码答案。见stackoverflow.com/help/how-to-answer
  • 不确定是什么问题,我看到了一个有效的实现和一个非常简单的示例,说明如何根据分隔符拆分字符串并存储值。这里唯一的问题是他错过了添加“.toInt()”(考虑到我们想要将值存储到一个 int 数组中)。一切看起来都不错。干得好@Jan
【解决方案3】:

对于内存的动态分配,你需要使用malloc,即:

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

您还需要最大字符串长度。

【讨论】:

  • 你不一定需要malloc()。如果字符串在拆分操作和数据传输之间不会发生变化,那么在原始字符串中保留一组指向不同位置的指针是非常安全的。它也更快,使用更少的内存,并减少潜在的内存泄漏。
  • 是的,这可以工作,您只需要手动跟踪每个字符串的长度/结尾以避免重叠,因为除了最后一个之外不会有 '\0' 终止字符一。
【解决方案4】:

C 根据分隔符拆分字符串的方法是使用strtok(或strtok_r)。 另请参阅this 问题。

【讨论】:

  • strtok 已折旧。改用strsep
  • 被谁弃用了?十分钟的谷歌搜索只发现了 Microsoft Visual Studio C++ 中的弃用。 OP 正在编写一个 Arduino,它使用自己的 C 版本,所以一个函数在 Windows 中是否被弃用是完全无关紧要的。
【解决方案5】:

我认为您的想法是一个很好的起点。这是我使用的代码(使用以太网屏蔽解析 HTTP GET REST 请求)。

这个想法是使用一个while循环和lastIndexOf并将字符串存储到一个数组中(但你可以做其他事情)。

"request" 是您要解析的字符串(对我来说它被称为 request 因为......它是)。

    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] 时,我认为它们是一个编码问题......我也是一个初学者,所以我不掌握 chars vs string......

希望对你有帮助。

【讨论】:

    【解决方案6】:

    我相信这是最直接最快捷的方式:

    String strings[10]; // Max amount of strings anticipated
    
    void setup() {
      Serial.begin(9600);
      
      int count = split("L,-1,0,1023,0", ',');
      for (int j = 0; j < count; ++j)
      {
        if (strings[j].length() > 0)
          Serial.println(strings[j]);
      }
    }
    
    void loop() {
      delay(1000);
    }
    
    // string: string to parse
    // c: delimiter
    // returns number of items parsed
    int split(String string, char c)
    {
      String data = "";
      int bufferIndex = 0;
    
      for (int i = 0; i < string.length(); ++i)
      {
        char c = string[i];
        
        if (c != ',')
        {
          data += c;
        }
        else
        {
          data += '\0';
          strings[bufferIndex++] = data;
          data = "";
        }
      }
    
      return bufferIndex;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-04-01
      • 2012-06-27
      • 2011-01-10
      • 1970-01-01
      • 1970-01-01
      • 2013-08-19
      相关资源
      最近更新 更多