Separating commands from string?

Hello,

I wondered if anyone could advise? I am trying to write a command line interface which allows several commands be enter together as a string and we separate these for processing.

The commands are all in uppercase, and can be single or come with a value.

An example input could be   COMMAND SECONDCOMMAND:VALUE

The : symbol means a value is attached to this command, I thought perhaps I could use the strtok function to find the : values which would also give the command, here this would give SECONDCOMMAND:VALUE, but I wondered how I could locate the single commands?

I also thought I could create an object for each command, and it value such as:

struct{
string command;
string value;
}

I would be appreicate some guidance, should I perhaps be trying not use existing tools. And loop through the string line searching for uppercase letters?

Thank you
AntoniRyszard656Asked:
Who is Participating?
 
jkrConnect With a Mentor Commented:
>>Would I be able to parson through a char * as in this example does with a char[]?

Yes, definitely. However, that would fail if you used

char* str ="COMMAND1      COMMAND2:VALUE";

since this would be a 'const' string.

>>And should I enter the command line as a char * rather than a string?

How *are* you getting the command line now?
0
 
jkrCommented:
Even if you don't want to use existing tools, you should consider using 'getopt', which is a ready made interface for command line processing and seems to be ideal for your situation:

getopt.h
---------------------------------------------------------->8-------------------------------------------------
#ifndef UNIX    /* avoid conflict with stdlib.h */
int getopt(int argc, char **argv, char *opts);
extern char *optarg;
extern int optind;
#endif
---------------------------------------------------------->8-------------------------------------------------

getopt.c
---------------------------------------------------------->8-------------------------------------------------
/*
*  This is the AT&T public domain source for getopt(3).  It is the code
*  which was given out at the 1985 UNIFORUM conference in Dallas.
*  
*  There is no manual page.  That is because the one they gave out at
*  UNIFORUM was slightly different from the current System V Release 2
*  manual page.  The difference apparently involved a note about the
*  famous rules 5 and 6, recommending using white space between an
*  option and its first argument, and not grouping options that have
*  arguments.  Getopt itself is currently lenient about both of these
*  things.  White space is allowed, but not mandatory, and the last option
*  in a group can have an argument.  That particular version of the man
*  page evidently has no official existence.  The current SVR2 man page
*  reflects the actual behavor of this getopt.
*/

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

/*LINTLIBRARY*/
#ifndef NULL
#define NULL      0
#endif
#define EOF      (-1)
#define ERR(str, chr) (opterr ? fprintf(stderr, "%s%s%c\n", argv[0], str, chr) : 0)

int      opterr = 1;
int      optind = 1;
int      optopt = 0;
char      *optarg = 0;

int
getopt(int argc, char **argv, char *opts)
{
      static int sp = 1;
      register int c;
      register char *cp;

      if(sp == 1) {
            if(optind >= argc || (argv[optind][0] != '+' &&
               argv[optind][0] != '-') || argv[optind][1] == '\0')
                  return EOF;
            else if(strcmp(argv[optind], "--") == 0) {
                  optind++;
                  return EOF;
            }
            /* '+' for config options, '+' should not be in the opts list */
            if (argv[optind][0] == '+') {
                  optarg = argv[optind++] + 1;
                  return '+';
            }
      }
      optopt = c = argv[optind][sp];
      if(c == ':' || (cp=strchr(opts, c)) == NULL) {
            ERR(": illegal option -- ", c);
            if(argv[optind][++sp] == '\0') {
                  optind++;
                  sp = 1;
            }
            return '\0';
      }
      if(*++cp == ':') {
            if(argv[optind][sp+1] != '\0')
                  optarg = &argv[optind++][sp+1];
            else if(++optind >= argc) {
                  ERR(": option requires an argument -- ", c);
                  sp = 1;
                  return '\0';
            } else
                  optarg = argv[optind++];
            sp = 1;
      } else {
            if(argv[optind][++sp] == '\0') {
                  sp = 1;
                  optind++;
            }
            optarg = NULL;
      }
      return c;
}
---------------------------------------------------------->8-------------------------------------------------

For more info, see http://www.opengroup.org/onlinepubs/007908799/xsh/getopt.html
0
 
AntoniRyszard656Author Commented:
Thank you for replying.

Do you think an alternative could be to use the sscanf() function and change it's search value.

For example %s to find the separate commands and : to find the commands with a value attached.

Or use the strtok() and change it search value.

Do you think this could work?

0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

 
AntoniRyszard656Author Commented:
For example, if I used the strtok as below, I thought this would find all the separate commands.

  char * pch;
 
  pch = strtok (str," ");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ");
  }

  And if I used : this would I find all the command:value in a string

  char * pch;
 
  pch = strtok (str,":");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, ":");
  }

Would you recommend this approach?

Thanks
0
 
jkrCommented:
>>Would you recommend this approach?

It seems a feasible approach. However, 'getopt()' has been used and testd over ages, thus *I* would avoid re-inventing the wheel.
0
 
AntoniRyszard656Author Commented:
Hello,

I have used sscanf() and strtok() before and thought it would a good idea to use them.

The problem is, the command are inputted as a string but these parson function work with char arrays.

Is there any function in C++ to change string to a char array?

Thanks
0
 
jkrCommented:
>>Is there any function in C++ to change string to a char array?

You mean a 'std::string'? Sure, use

string str;

// ...

char* psz = strdup ( str.c_str());
0
 
AntoniRyszard656Author Commented:

Would this also work to create an char[] from a string?

for example  char input[] = strdup(str.c_str());
0
 
jkrCommented:
Not really using this syntax. But, actually, there is no difference between

char* psz = new char [ 255];

and

char ac [ 255];

What you always can do is

char ac [ 255];

if ( str.size() < 255) {

    strcpy ( ac, str.c_str());
}
0
 
AntoniRyszard656Author Commented:
Hello,

Would I be able to parson through a char * as in this example does with a char[]?

  char str[] ="COMMAND1      COMMAND2:VALUE";
  char * pch;

  pch = strtok (str," ");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ");
  }
0
 
AntoniRyszard656Author Commented:

And should I enter the command line as a char * rather than a string?

Thanks
0
 
AntoniRyszard656Author Commented:
Thank you for replying.

I decided the best approach would be to create a char[], at the moment the commands are enter as strings. Is there any different between char * and a string?

Below is example parson method, using the char[]. I wondered also, if I decided to use a char * rather an string. How could I compare a char * for example to test if the char * had a value PARSON.

Using a string this would be just if(command == "PARSON")

Thank you

void exampleParson(string script){    
   char input [sizeof script];
   
   for(int i = 0; i < sizeof input; i++){
      input[i] = script[i];
   }      

   char * parson;
   parson = strtok (input," ");
   
   while(parson != NULL){
      printf ("%s\n",parson);
      parson = strtok(NULL, " ");  
   }

}
0
 
AntoniRyszard656Author Commented:
Hello,

The commands are all entered as uppercase, and we store the input as a string. But also the user can enter lowercase words which makes the input read like a sentence. My hope was to just pass over the lowercase words, and separate the uppercase commands from the string.

An example could be:     in this script we have COMMAND1 and COMMAND2:VALUE

And some how locate COMMAND1, AND COMMAND2:VALUE from the script.

And finally separate any command with a value, and store both the commands and values.

I wrote this method to try and firstly locate,  COMMAND1  COMMAND2:VALUE

I would appreciate if you could offer any guidance.

Thanks

typedef struct input{
   string strings;
};

vector <input> stringVect;

void parsonMethod(string script){    
   int i = 0; string parson= "";

   while(i < sizeof script){
      if(isupper(script[i])){
     
         while(i < sizeof script){        
            parson = "";
           
            if(isupper(script[i]) || script[i] == ":"){
               parson = parson + script[i];
               i++;
            }
            else{
               i++;
               break;
            }
         }

         input newinput;
         newinput.strings =  parson;
         stringVect.push_back(newinput);                      
      }
      else{
         i++;
      }
   }

}
0
 
SteHCommented:
If you already have STL string s why not use string::find to locate ' ' and ':'

And stringVect should be declared as:

vector<string> stringVect;

This allows access to them using stringVect[i] and not stringVect[i].strings and stringVect.push_back (parson)

int pos, pos2;
do {
  pos = script.find (' ');
  string command = script.substr (0, pos); // or pos-1?  and command could be renamed to parson to match the examples above.
                                                             // but I find command a more intuitive name.
  pos2 = script.find_first_not_of (" ");
  script = script.substr (pos2); // remove found command and trailing whitespaces.
  pos2 = command.find (':');
  if (pos2 != string::npos) { // : found in string
     command = command.substr (0, pos2-1); // take only part before colon
  }
  stringVect.push_back (command);
} while (pos != string::npos)
0
 
AntoniRyszard656Author Commented:
Thank you for replying.

An example input could be:

in this script we have COMMAND1 and COMMAND2:VALUE

The input includes the lowercase words, and I thought the only approach separate the uppercase words, would be:

typedef struct input{
   string strings;
};

vector <input> stringVect;

void parsonMethod(string script){    
   int i = 0; string parson= "";

   while(i < sizeof script){
      if(isupper(script[i])){
     
         while(i < sizeof script){        
            parson = "";
           
            if(isupper(script[i]) || script[i] == ":"){
               parson = parson + script[i];
               i++;
            }
            else{
               i++;
               break;
            }
         }

         input newinput;
         newinput.strings =  parson;
         stringVect.push_back(newinput);                      
      }
      else{
         i++;
      }
   }

}

This would hopefully create two objects from the input line:
COMMAND1
COMMAND2:VALUE

And then write another separating method to separate COMMAND's and VALUE's.

I just if anyone knew of some other approach?

Thank you
0
 
SteHConnect With a Mentor Commented:
The line
         while(i < sizeof script){        
should be
         while (i < script.size ())   // or
         while (i < script.length ())
To check if a string is all uppercase do
   string string1, string2;
   // fill string1 with token
   string2 = do_toupper(string1.begin (), string1.end()) // make string2 be string1 in uppdercase.
   if (string1 == string2) {
        // token was all uppercase.
   }
 
0
 
AntoniRyszard656Author Commented:
Thanks.

In the code below, I managed to separate the input into individual words, and store these in a vector.

I hoped now loop through this vector, and when we find a uppercase word divide this word into two strings. And create another vector of objects, from the uppercase words.

For example, building the objects using:

struct{
   string field1;
   string field2;
};

The first object would hold COMMAND in field1, and the second object would contain COMMAND1 in field1 and 1221 in field2. Could anyone advise, how best to further divide the strings?

Thank you  

   vector <string> stringVect;
   vector<string>::iterator it;
   
   string script = "in this script we have COMMAND1 and COMMAND2:1221";
   char array[script.length()];
   strcpy(array, script.c_str());
         
   char * parson = strtok(array," ");
           
   while(parson !=NULL){      
      stringVect.push_back(parson);
      parson = strtok(NULL, " ");  
   }
   
   int i = 0;
   for (it = stringVect.begin(); it != stringVect.end(); ++it){  
      cout << endl << *it;
   }
0
 
AntoniRyszard656Author Commented:
Sorry my mistake:

struct commands{
   string field1;
   string field2;
};

vector<commands>newVector;

The first object would hold COMMAND1 in field1, and the second object would contain COMMAND2 in field1 and 1221 in field2.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.