Рассмотрим еще одну реализацию. Run .
#include <cctype> // <ctype.h> for isspace()
/**
* Parse out the next non-space word from a string.
* @note No nullptr protection
* @param str [IN] Pointer to pointer to the string. Nested pointer to string will be changed.
* @param word [OUT] Pointer to pointer of next word. To be filled.
* @return pointer to string - current cursor. Check it for '\0' to stop calling this function
*/
static char* splitArgv(char **str, char **word)
{
constexpr char QUOTE = '\'';
bool inquotes = false;
// optimization
if( **str == 0 )
return NULL;
// Skip leading spaces.
while (**str && isspace(**str))
(*str)++;
if( **str == '\0')
return NULL;
// Phrase in quotes is one arg
if( **str == QUOTE ){
(*str)++;
inquotes = true;
}
// Set phrase begining
*word = *str;
// Skip all chars if in quotes
if( inquotes ){
while( **str && **str!=QUOTE )
(*str)++;
//if( **str!= QUOTE )
}else{
// Skip non-space characters.
while( **str && !isspace(**str) )
(*str)++;
}
// Null terminate the phrase and set `str` pointer to next symbol
if(**str)
*(*str)++ = '\0';
return *str;
}
/// To support standart convetion last `argv[argc]` will be set to `NULL`
///\param[IN] str : Input string. Will be changed - splitted to substrings
///\param[IN] argc_MAX : Maximum a rgc, in other words size of input array \p argv
///\param[OUT] argc : Number of arguments to be filled
///\param[OUT] argv : Array of c-string pointers to be filled. All of these strings are substrings of \p str
///\return Pointer to the rest of string. Check if for '\0' and know if there is still something to parse. \
/// If result !='\0' then \p argc_MAX is too small to parse all.
char* parseStrToArgcArgvInsitu( char *str, const int argc_MAX, int *argc, char* argv[] )
{
*argc = 0;
while( *argc<argc_MAX-1 && splitArgv(&str, &argv[*argc]) ){
++(*argc);
if( *str == '\0' )
break;
}
argv[*argc] = nullptr;
return str;
};
Код использования
#include <iostream>
using namespace std;
void parseAndPrintOneString(char *input)
{
constexpr size_t argc_MAX = 5;
char* v[argc_MAX] = {0};
int c=0;
char* rest = parseStrToArgcArgvInsitu(input,argc_MAX,&c,v);
if( *rest!='\0' ) // or more clear `strlen(rest)==0` but not efficient
cout<<"There is still something to parse. argc_MAX is too small."<<endl;
cout << "argc : "<< c << endl;
for( int i=0; i<c; i++ )
cout<<"argv["<<i<<"] : "<<v[i] <<endl;
/*//or condition is `v[i]`
for( int i=0; v[i]; i++ )
cout<<"argv["<<i<<"] : "<<v[i] <<endl;*/
}
int main(int argc, char* argv[])
{
char inputs[][500] ={
"Just another TEST\r\n"
, " Hello my world 'in quotes' \t !"
, "./hi 'Less is more'"
, "Very long line with \"double quotes\" should be parsed several times if argv[] buffer is small"
, " \t\f \r\n"
};
for( int i=0; i<5; ++i ){
cout<<"Parsing line \""<<inputs[i]<<"\":"<<endl;
parseAndPrintOneString(inputs[i]);
cout<<endl;
}
}
Выход:
Parsing line "Just another TEST\r\n":
argc : 3
argv[0] : Just
argv[1] : another
argv[2] : TEST
Parsing line " Hello my world 'in quotes' !":
There is still something to parse. argc_MAX is too small.
argc : 4
argv[0] : Hello
argv[1] : my
argv[2] : world
argv[3] : in quotes
Parsing line "./hi 'Less is more'":
argc : 2
argv[0] : ./hi
argv[1] : Less is more
Parsing line "Very long line with "double quotes" should be parsed several times if argv[] buffer is small":
There is still something to parse. argc_MAX is too small.
argc : 4
argv[0] : Very
argv[1] : long
argv[2] : line
argv[3] : with
Parsing line "
":
argc : 0