🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

2回答

10664閲覧

【Arduino】特定文字での文字列の分割(split関数に似たもの)

退会済みユーザー

退会済みユーザー

総合スコア0

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2019/09/11 08:37

やりたいこと

Arduinoで特定文字での文字列の分割したいです。
func関数は元の文字列、分割文字、indexを受け取ってindexに沿った文字列を返します。
分割数に指定はなく、分割文字がいくつでも結果を返せる関数です。

完成例1: String str = "Arduino ok"; String part0 = func(str,' ',0); //結果part0 = Arduino String part1 = func(str,' ',1); //結果part1 = ok 完成例2: String str = "Arduino ok hallo"; String part0 = func(str,' ',0); //結果part0 = Arduino String part1 = func(str,' ',1); //結果part1 = ok String part2 = func(str,' ',2); //結果part2 = hallo

ソースコード

Arduino

1#include <stdio.h> 2#include <string.h> 3 4char recieveData[256]; 5char sendData[256]; 6int count = 0 ; 7 8String Func(String data, char separator, int index) 9{ 10 int found = 0; 11 int strIndex[] = {0, -1}; 12 int maxIndex = data.length(); 13 int endcheck = false; 14 15 for(int i=0; i < maxIndex; i++){ 16 if( data.charAt(i) == separator ){ 17 found++; 18 if ( found == index ){ strIndex[0] = i+1; } 19 if ( found == index+1 ){ strIndex[1] = i; endcheck=true; } 20 if(endcheck){ break; } 21 } 22 } 23 //確認用 24 Serial.print("Func関数の確認: "); 25 Serial.print("found" + String(found) + " "); 26 Serial.print("index" + String(index) + " "); 27 Serial.print("strIndex[0]:" + String(strIndex[0]) + " "); 28 Serial.println("strIndex[1]:" + String(strIndex[1])); 29 return (strIndex[1]==-1) ? data.substring(strIndex[0]) : data.substring(strIndex[0], strIndex[1]); 30} 31//分割文字の数 32int Keywordcounter(String Original,char Keyword) { 33 int Keywordcount = 0; 34 for (int i = 0; i < Original.length(); i++){ 35 if (Original.charAt(i) == Keyword) { Keywordcount++; } 36 } 37 return Keywordcount; 38} 39 40void Check_command(String command) { 41 String part[] = {"\0"}; // 分割された文字列を格納する配列 42 char buf[256]; 43 44 command.remove(command.length()-1); //'\n'を消去 45 Serial.println("分割前確認:" + String(command)); 46 47 //分割文字の数 48 int count = Keywordcounter(command, ' '); 49 50  //文字列 = Func(元の文字列,分割文字列,分割した後何番目の文字列か) 51 for (int i = 0; i < count+1; i++){ 52 part[i] = Func(command,' ',i); 53 } 54 55 Serial.print("分割後確認 "); 56 for (int i = 0; i < count+1; i++){ 57 Serial.print(String(i) + ":" + part[i] + " "); 58 } 59 Serial.println(""); 60 Serial.println(""); 61} 62 63void setup() { 64 Serial.begin(9600);//シリアル通信のレートを9600に設定 65} 66 67void loop() { 68 if (Serial.available()) { 69 recieveData[count] = Serial.read(); // 文字列受信 70 if (count > 30 || recieveData[count] == '\n') { 71 Check_command(String(recieveData)); 72 for (int i =0; i <= count; i++) { recieveData[count] == '\0'; } 73 count=0; 74 } else { count++; } 75 } 76} 77

実行結果

分割文字が1文字の場合は成功しますが、2個以上の場合うまくいきません。
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t_obara

2019/09/11 09:22

foundが0なので、Funcに渡されたdataの内容を確認してみては?
guest

回答2

0

ベストアンサー

まず気のついたところを

String part[] = {"\0"}; // 分割された文字列を格納する配列

これでは、partの中身はこの文字列分しか確保されません
これではまずいですね

String part[1] = {"\0"};

ってことで、
part[1]="なんちゃら";
とするとアクセス違反です

投稿2019/09/11 08:55

編集2019/09/11 09:57
y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/09/11 12:26

ありがとうございます。 int count = Keywordcounter(command, ' '); の後で、 String part[count+1]; と宣言したらおおよそ直りました。 他にも悪いところがあったようで、 void loop()内も以下のように修正したら完全に良くなりました。 誤: for (int i =0; i <= count; i++) { recieveData[count] == '\0'; } 正: for (int i =0; i <= count; i++) { recieveData[i] = '\0'; }
guest

0

y_waiwaiさんご指摘のところを直せばそれっぽく動きますね。配列の範囲外への書き込みでいろいろデータ破壊が起こっているのでしょう。

C++

1void Check_command(String command) { 2 //String part[] = {"\0"}; // これはやめる 3<> 4 5 //分割文字の数 6 int count = Keywordcounter(command, ' '); 7//どちらかでpartの配列の要素数をcount個に宣言 8 String* part = new String[count]; 9 //String part[count + 1]; 10 <> 11 delete[] part; //newで配列を作ったときはdeleteしておく 12}

とかなんとか。
(書いてるうちに解決済になっちゃった。receiveData[count]は気が付かなかった...)

それはともかく、String::indexOf()という関数があるのだから使いませんか。

for(int i=0; i < maxIndex; i++){ if( data.charAt(i) == separator ){

のループは

for (int i = 0; i < index ; i++) { strIndex[0] = data.indexOf(separator, strIndex[0])+1; } strIndex[1] = data.indexOf(separator, strIndex[0]);

で用が足りるし、Keywordcounter()関数も

//分割文字の数 int Keywordcounter(String Original, char Keyword) { int Keywordcount = 0; int sep = 0; while ( (sep = Original.indexOf(Keyword, sep)) > 0) { Keywordcount++; sep++; } return Keywordcount; }

とか書けます。
あ、あと直してませんが、charの値にKeywordという名前はちょっと不適切な感じがします。

投稿2019/09/11 12:34

thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問