web-dev-qa-db-ja.com

文字列を文字列配列に分割

私はarduinoのプログラミングをいじっていましたが、今日、非常に限られたCの知識では解決できない問題に遭遇しました。ここにその様子を示します。 Arduinoにシリアル入力(deviceID、command、commandparameters)を送信するPCアプリケーションを作成しています。この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:関数 'void splitCommand(String、char)'で:

SerialEvent:68:エラー:引数 '1'から 'char *への' String 'から' char * 'への変換はできませんstrtok(char *、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]);
    }
}
13
NightWalker

これは古い質問ですが、役立つコードをいくつか作成しました。

 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」を出力する必要があります。インデックス0が「hi」を返すか、インデックス5が「test」を安全に返すようにすることもできます。

この助けを願っています!

実装:

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
6
Jan

あなたのアイデアは良い出発点だと思います。これは私が使用するコードです(イーサネットシールドを使用したHTTP GET REST要求を解析するため))。

アイデアは、whileループとlastIndexOf ofを使用して文字列を配列に格納することです(ただし、他のことを実行できます)。

「リクエスト」は解析したい文字列です(私にとってはリクエストと呼ばれていました。

    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]を印刷しようとすると、エンコーディングの問題が発生します。

それが役に立てば幸い。

0
Romain Bruckert

メモリを動的に割り当てるには、mallocを使用する必要があります。

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

文字列の最大長も必要です。

0
3Pi

区切り文字に基づいて文字列を分割するCの方法は、 strtok (またはstrtok_r)。 this の質問も参照してください。

0
markgz