1

I have a character array like below:

char array[] = "AAAA... A1... 3. B1.";

How can I split this array by the string "..." in Arduino? I have tried:

ptr = strtok(array, "...");

and the output is the following:

AAAA,
 A1,
 3,
 B1

But I actually want output to be

AAAA,
A1,
3.B1.

How to get this output?

edit:

My full code is this:

char array[] = "AAAA... A1... 3. B1.";
char *strings[10];
char *ptr = NULL;`enter code here` 

void setup()
{
       Serial.begin(9600);

       byte index = 0;
       ptr = strtok(array, "...");  // takes a list of delimiters
       while(ptr != NULL)
       {
            strings[index] = ptr;
            index++;
            ptr = strtok(NULL, "...");  // takes a list of delimiters
       }

       for(int n = 0; n < index; n++)
       {
          Serial.println(strings[n]);
       }
    }
10
  • 2
    Welcome to SO: You write: "I have tried strtok() function but ..." Fine :-) Now please post that code here and explain what goes wrong. Then we can help you correct the code. BTW: strtok is probably the wrong function for this but when you post your code using strtok we'll be able to send you in the right direction. Commented Feb 22, 2019 at 9:01
  • @4386427 Thank you I a new to stackoverflow.I made the edits Commented Feb 22, 2019 at 9:36
  • @StefanBecker made the edit please check the question Commented Feb 22, 2019 at 9:38
  • 2
    You could use strstr and iterate yourself. strtok finds any of the characters in delimeters, so "..." will result in the same as ".". Commented Feb 22, 2019 at 9:41
  • 1
    Now that you know that strtok does not distinguish a single '.' from multiple '...' you could show us the version you tried with strstr. Commented Feb 22, 2019 at 10:21

4 Answers 4

3

The main problem is that strtok does not find a string inside another string. strtok looks for a character in a string. When you give multiple characters to strtok it looks for any of these. Consequently, writing strtok(array, "..."); is exactly the same as writing strtok(array, ".");. That is why you get a split after "3."

There are multiple ways of doing what you want. Below I'll show you an example using strstr. Unlike strtokthe strstr function do find a substring inside a string - just what you are looking for. But.. strstr is not a tokenizer so some extra code is required to print the substrings.

Something like this should do:

int main()
{
  char array[] = "AAAA... A1... 3. B1...";

  char* ps = array;
  char* pf = strstr(ps, "..."); // Find first substring
  while(pf)
  {
    int len = pf - ps;          // Number of chars to print
    printf("%.*s\n", len, ps);
    ps = pf + 3;
    pf = strstr(ps, "...");     // Find next substring
  }
  return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

0

You can implement your own split as strtok except the role of the second argument :

#include <stdio.h>
#include <string.h>

char * split(char *str, const char * delim)
{
  static char * s;
  char * p, * r;

  if (str != NULL)
    s = str;

  p = strstr(s, delim);

  if (p == NULL) {
    if (*s == 0)
      return NULL;

    r = s;
    s += strlen(s);
    return r;
  }

  r = s;
  *p = 0;
  s = p + strlen(delim);

  return r;
}

int main()
{
  char s[] = "AAAA... A1... 3. B1.";
  char * p = s;
  char * t;

  while ((t = split(p, "...")) != NULL) {
    printf("'%s'\n", t);
    p = NULL;
  }

  return 0;
}

Compilation and execution:

/tmp % gcc -g -pedantic -Wextra s.c
/tmp % ./a.out
'AAAA'
' A1'
' 3. B1.'
/tmp % 

I print between '' to show the return spaces, because I am not sure you want them, so delim is not only ... in that case

Comments

0

Because you tagged this as c++, here is a c++ 'version' of your code:

#include <iostream>
using std::cout;
using std::endl; 

#include <vector>
using std::vector;

#include <string>
using std::string;


class T965_t
{
   string         array;
   vector<string> strings;

public:
   T965_t() : array("AAAA... A1... 3. B1.") 
      {
         strings.reserve(10);
      }

   ~T965_t() = default;

   int operator()() { return setup(); } // functor entry

private: // methods

   int setup()
      {
         cout << endl;
         const string pat1 ("... ");
         string s1 = array; // working copy

         size_t indx = s1.find(pat1, 0); // find first ... pattern
         // start search at ---------^
         do
         {
            if (string::npos == indx)  // pattern not found
            {
               strings.push_back (s1); // capture 'remainder' of s1
               break;                  // not found, kick out
            }

            // else 
            // extract --------vvvvvvvvvvvvvvvvv
            strings.push_back (s1.substr(0, indx));  // capture
            // capture to vector

            indx += pat1.size(); // i.e. 4

            s1.erase(0, indx); // erase previous capture 

            indx = s1.find(pat1, 0);          // find next

         } while(true);

         for(uint n = 0; n < strings.size(); n++)
            cout << strings[n] << "\n";

         cout << endl;
         return 0;
      }

}; // class T965_t

int main(int , char**) { return T965_t()(); } // call functor

With output:

AAAA
A1
3. B1.

Note: I leave changing "3. B1." to "3.B1.", and adding commas at end of each line (except the last) as an exercise for the OP if required.

2 Comments

I got a chuckle out load thinking of an ATMega48 implementing this.
The original code was also C++, of a style more appropriate to Arduino. This code is not Arduino framework code. The Setup() function in the original code is part of the Arduino framework to perform initialisation.
0

I looked for a split function and I didn't find one that meets my requirement, so I made one and it works for me so far, of course in the future I will make some improvements, but it got me out of trouble.

But there is also the strtok function and better use that. https://www.delftstack.com/es/howto/arduino/arduino-strtok/

I have the split function

Arduino code:

void split(String * vecSplit, int dimArray,String content,char separator){
if(content.length()==0)
    return;
 content = content + separator;
 int countVec = 0;
 int posSep = 0;
 int posInit = 0;
 while(countVec<dimArray){
   posSep = content.indexOf(separator,posSep);
   if(posSep<0){
    return;
   } 
 countVec++;       
 String splitStr = content.substring(posInit,posSep);
 posSep = posSep+1; 
 posInit = posSep;
 vecSplit[countVec] = splitStr;
 countVec++;    

} }

Llamada a funcion:

smsContent = "APN:4g.entel;DOMAIN:domolin.com;DELAY_GPS:60";
String vecSplit[10];

split(vecSplit,10,smsContent,';');
for(int i = 0;i<10;i++){
   Serial.println(vecSplit[i]);    
}

String input: APN:4gentel;DOMAIN:domolin.com;DELAY_GPS:60

Output:

  • APN:4g.entel
  • DOMAIN:domolin.com
  • DELAY_GPS:60
  • RESET:true

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.