String Manipulation

19 Jul 2012

Does anyone know of a good place to find information on manipulation of strings and things that works on the mbed? I've been searching for a couple days trying to find what I can to piece together something that will allow me to manipulate some strings from text files, and other sources with the mbed. So far, I have found very little..unless I'm missing some information on this site somewhere.. There's a little here and there, and I've almost got what I want, but I'd love to find something that's a kind of reference sheet...

On a related note, does anyone know if I can use outside libraries like string.h or something similar for the mbed? I've seen some reference to outside libraries, etc.. but can't seem to find it again, and I certainly don't know the limits in that respect....

As usual, any help is greatly appreciated!!!

19 Jul 2012

I don't know if this is what you meant by string manipulation but it should at least get you started. It is not mbed specific, obviously, but as the mbed has an implementation of C++ all the functions should remain working. You can always try as I do, throw it in VC++ or Code:Blocks and try it out on your computer to make sure your logic works then point it over to mbed.

http://www.mochima.com/tutorials/strings.html

Matt

19 Jul 2012

Yes Matt, that's pretty close to what I've been looking for.. I've been using http://www.cplusplus.com/reference/ for sometime but not everything seems to translate well over to the mbed.. Currently, I'm just trying things like parsing a comma delimited string and get a bunch of gps coordinates from it... It's actually a kml file, but I don't want to go through everything I'd have to in order to properly parse an xml file.. I'm taking baby steps on this one.... I've tried many examples, and am using the following libraries as a result of a bunch of stuff I've found... I was just hoping to find something that shows what's supported and maybe some examples for the mbed.. If I figure this out, maybe I can even write something up for others.. =)

#include "iostream"
#include "stdio.h"
#include "string"
#include "algorithm"
19 Jul 2012

So far, this is an example of what I'm interested in doing... This code is a complete mess, and its thrown together from what I could scrounge up and make compile... I'd like to find something a little more elegant but still lightweight... and also something that works would be nice... I just hate spending days trying to find some workable solution for something that is relatively simple...but then again, strings have always tripped me up across different languages...

int numberOfFields;
    //#define NUM_FIELDS  (12) //number of comma seperated values in the data...TODO does this remain constant?
    //char* pFields[int NUM_FIELDS];
// This function seperates the single input string in to numFields substrings
void ParseFields(char* inputBuffer, char** pFields, uint32_t numFields, char* delimiterChars) {
    char* pString = inputBuffer;
    char* pField;
    
numberOfFields = numFields;
    
    for (uint32_t i=0; i<numFields; i++) {
        pField = strtok(pString, delimiterChars);

        if (pField != NULL) {
            pFields[i] = pField;
        } else {
            pFields[i] = "";
        }

        pString = NULL; //to make strtok continue parsing the next field rather than start again on the original string (see strtok documentation for more details)
    }
}

int count_Commas(string s) {
  int count = 0;

  for (int i = 0; i < s.size(); i++)
    if (s[i] == ',') count++;

  return count;
}

int main(int argc, char* argv[]) {
    led2 = 1;
    pc.baud(921600);
    FILE *fp = fopen( "/" FSNAME "/example.kml", "r");
    printf("\nLoading example file:\n");
    led1 = 1;
//    fp = fopen( "/" FSNAME "/example.kml", "r");
    if ( fp == NULL ) {
        error("Could not open file for read operation.\n");
    }
    int wp = 0;
    char buf[256];
    for (int n=59; n>0; n--) {
        fgets(buf, sizeof(buf), fp);
        if (n == 5) {
//            printf("%s\n\n", buf);

char* pFields[numberOfFields];
            ParseFields(buf, pFields, count_Commas(buf), ",");
printf("Example Coordinate Count: %i\n\n", numberOfFields);

            for (int i=0; i<numberOfFields; i++) {
                if (i % 2 == 0) {
                    char *str = (char*) malloc(50 * sizeof(char));
                    strcpy(str, pFields[i]);

                    while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '2')
                        str++;

                    int len = strlen(str);

                    while (len >= 0 && (str[len - 1] == ' ' || str[len - 1] == '\t' || *str == '\n')    ) {
                        *(str + len - 1) = '\0';
                        len--;
                    }
                    wp++;
                    printf("EXAMPLE: %i\n", wp);
                    printf("    LONGITUDE:%s\n", str);
                } else {
                    char *str = (char*) malloc(50 * sizeof(char));
                    strcpy(str, pFields[i]);

                    while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '2')
                        str++;

                    int len = strlen(str);

                    while (len >= 0 && (str[len - 1] == ' ' || str[len - 1] == '\t' || *str == '\n')    ) {
                        *(str + len - 1) = '\0';
                        len--;
                    }
                    printf("    LATITUDE:%s\n\n", str);
                }
            }

        }
    }
    fclose(fp);
    led1 = 0;
    printf("\nExample Data loaded...\n");
}
20 Jul 2012

Well I'm actually working on a project reading from CSV files myself and having a hell of a time with it. If I get it working as a class in the near future I'll post it to the cookbook as a CSV manipulation library!

Thanks for the idea and good luck with yours

20 Jul 2012

Hey Matt, I hear ya.. I actually found this in the cookbook... http://mbed.org/users/hlipka/code/csv_parser/ Says it's a csv parser, but at 4am yesterday it looked a bit complex... I might take a fresh look.. I figured someone has to have something... There's also an xml parser, http://mbed.org/users/hlipka/code/spxml/ ... but it too looks complicated...

If I find an answer, I'll be sure to throw it up here.. I'm there's others whom might find it useful..

20 Jul 2012

Hey this is what I use to process NMEA strings, its entirely STL but there is really no reason to use a vector,

    std::vector<std::string> _fields;
    void interpretData(SimpleSerialProtocol::Packet* packet) {
        std::string raw_data( (char *) packet->_data);
        std::string  temp;
        while (raw_data.find(",", 0) != std::string::npos) {
            size_t  pos = raw_data.find(",", 0);
            temp = raw_data.substr(0, pos);
            raw_data.erase(0, pos + 1);
            if (temp.size() == 0) {
                temp = "0";
            }
            _fields.push_back(temp);
        }
        _fields.push_back(raw_data);
    }

I'd say its very inefficient, but easy to follow, and I wasn't worried about performance as its using strings for communication anyway

21 Jul 2012

Thanks Chris... That looks useful... I'm certainly learning more about this stuff as I go...

I found a pretty workable solution so far.. I think trying to parse the kml file might have been a little ambitious on my part at this date... So, I wrote a program in VB to parse out the kml into a simpler format... I then wrote this code to pull the latitudes and longitudes from that file..

#include "mbed.h"
#include "iostream"
#include "string"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

LocalFileSystem local("local");
Serial pc(USBTX, USBRX);

int main() {
    led1 = 1;
    pc.baud(921600);
    printf("Parsing:\r\n");
    wait(1);
    led2 = 1;
    FILE *fp = fopen( "/local/test.txt", "r");
    printf("\nLoading file:\n");
    if ( fp == NULL ) {
        error("Could not open file for read operation.\r\n");
        led3 = 1;
    }
    char buf[256];
    int n = 0;
    string coord;
    string longitude;
    string latitude;
    
    while (n <= 667) {
        n++;
        fgets(buf, sizeof(buf), fp);

        size_t found;
        string str(buf);
        
        found=str.find("COORD:");
        if (found!=string::npos) {
            size_t f = str.find("COORD:");
            waypoint = str.replace(f, std::string("COORD:").length(), "\0");
            printf("\nFound Coord: %s", coord);
        }
        found=str.find("LON:");
        if (found!=string::npos) {
            size_t f = str.find("LON:");
            longitude = str.replace(f, std::string("LON:").length(), "\0");
            printf("        LONGITUDE: %s", longitude);
        }
        found=str.find("LAT:");
        if (found!=string::npos) {
            size_t f = str.find("LAT:");
            latitude = str.replace(f, std::string("LAT:").length(), "\0");
            printf("        LATITUDE:  %s", latitude);
        }
        
        led2 = 0;
    }
    printf("Closing File...\r\n");
    fclose(fp);
    led1 = 0;
    wait(1);
}

It doesn't seem perfect...But it works.. I know there's something I am still missing because I get a compiler error: non-POD class type passed through elipsis... Not sure what that's all about et... =/

21 Jul 2012

I think your compile errors probably that your passing an STL std::string into printf, I didnt think that would compile at all,the std::string has a method called c_str() that returns a normal null terminated char*

printf("\nFound Coord: %s", coord.c_str());

all non-POD means is that its not a built in simple type, such as int, or char

what is this magic number 667? shouldnt you check for end of line, or end of file?

21 Jul 2012

Got bored and wrote a simple kml,xml parser, puts everything into a tree in memory so don't feed it large files, havn't written any simple way to access the data you just have to know where it is in the tree. so if you want to stick with the kml file format i hope this is of some help,

[Repository '/users/p3p/code/KMLParser/' not found]

also its only been tested on 1 file

21 Jul 2012

Thansks Chris! That is very helpful... The magic number 667 actually is a total coincidence.. I'd love to figure out how to check for end of file... But I can't seem to figure that one out yet as well...! For my test, I basically went to google earth, created a random path and saved it as a kml file, then ran that through my vb app to strip it down to just coordinates...

I'll be sure to check out your parser... Thank you very much for posting that... And if you have a clue of where to point me to be able to find the end of file, or length, etc... I'd really appreciate it... =)

21 Jul 2012

the source of the parser should help you =), line 21 is

    while(!feof(fp) && !ferror(fp) ){

feof checks for the eof, and ferror for anything else that might have blown up

21 Jul 2012

http://www.cplusplus.com/reference/clibrary/cstdio/ is a good reference, to get the length of the file you need to seek to the end and check the position,

fseek(file, 0, SEEK_END);
std::size_t filelength = ftell(file);

22 Jul 2012

Excellent! Thank you Chris!! Thank you for providing an example and an explanation...very helpful information..!! Hopefully, I'll get better at this..and maybe I can help someone else in the future.. =)