Is there any way to do this with strtok
function? or any suggestions ?
Example :
Insert "hello world" to dbms
Result:
Insert
"hello world"
to
dbms
Is there any way to do this with strtok
function? or any suggestions ?
Example :
Insert "hello world" to dbms
Result:
Insert
"hello world"
to
dbms
strtok
or any other function in the standard C library can't do this for you. To get it, you have to write code for it yourself, or you have to find some existing code in some external library.
This function takes delimiting, openblock and closeblock characters. Delimiting characters are ignored within the block and closing block characters must match the opening block characters. The example splits on space and blocks are defined by quote and brackets, braces and <>. Thanks to Jongware for comments!
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
char *strmbtok ( char *input, char *delimit, char *openblock, char *closeblock) {
static char *token = NULL;
char *lead = NULL;
char *block = NULL;
int iBlock = 0;
int iBlockIndex = 0;
if ( input != NULL) {
token = input;
lead = input;
}
else {
lead = token;
if ( *token == '\0') {
lead = NULL;
}
}
while ( *token != '\0') {
if ( iBlock) {
if ( closeblock[iBlockIndex] == *token) {
iBlock = 0;
}
token++;
continue;
}
if ( ( block = strchr ( openblock, *token)) != NULL) {
iBlock = 1;
iBlockIndex = block - openblock;
token++;
continue;
}
if ( strchr ( delimit, *token) != NULL) {
*token = '\0';
token++;
break;
}
token++;
}
return lead;
}
int main (int argc , char *argv[]) {
char *tok;
char acOpen[] = {"\"[<{"};
char acClose[] = {"\"]>}"};
char acStr[] = {"this contains blocks \"a [quoted block\" and a [bracketed \"block] and <other ]\" blocks>"};
tok = strmbtok ( acStr, " ", acOpen, acClose);
printf ( "%s\n", tok);
while ( ( tok = strmbtok ( NULL, " ", acOpen, acClose)) != NULL) {
printf ( "%s\n", tok);
}
return 0;
}
output
this
contains
blocks
"a [quoted block"
and
a
[bracketed "block]
and
No luck using strtok()
.
Fun opportunity to employ a state machine.
#include <stdio.h>
void printstring(const char *frm, const char *to) {
fputc('<', stdout); // <...>\n Added for output clarity
while (frm < to) {
fputc(*frm++, stdout);
}
fputc('>', stdout);
fputc('\n', stdout);
}
void split_space_not_quote(const char *s) {
const char *start;
int state = ' ';
while (*s) {
switch (state) {
case '\n': // Could add various white-space here like \f \t \r \v
case ' ': // Consuming spaces
if (*s == '\"') {
start = s;
state = '\"'; // begin quote
} else if (*s != ' ') {
start = s;
state = 'T';
}
break;
case 'T': // non-quoted text
if (*s == ' ') {
printstring(start, s);
state = ' ';
} else if (*s == '\"') {
state = '\"'; // begin quote
}
break;
case '\"': // Inside a quote
if (*s == '\"') {
state = 'T'; // end quote
}
break;
}
s++;
} // end while
if (state != ' ') {
printstring(start, s);
}
}
int main(void) {
split_space_not_quote("Insert \"hello world\" to dbms");
return 0;
}
<Insert>
<"hello world">
<to>
<dbms>
Maybe you can use a regexp (ie Regular expressions in C: examples?)
Here an example of regex you can use: /([\w]+)|(\"[\w\ ]+\")/gi
To train yourself with regex you should also use: http://regex101.com/
You could do a first pass where strtok splits the string using the quote character as your delimiter. Then do a second pass with the space character as the delimiter on the resulting strings that were non-quoted.
Edited to add working source code:
bool quotStr = (*stringToSplit == '\"');
char* currQuot = strtok(stringToSplit, "\"");
char* next = NULL;
while(currQuot)
{
if(quotStr)
{
printf("\"%s\"\n", currQuot);
quotStr = false;
}
else
{
// remember where the outer loop strtok left off
next = strtok(next, "\0");
// subdivide
char* currWord = strtok(currQuot, " ");
while(currWord)
{
printf("%s\n", currWord);
currWord = strtok(NULL, " ");
}
quotStr = true;
}
currQuot = strtok(next, "\"");
next = NULL;
}
I believe this will still fail in the case of empty quoted strings, though...
My solution with strtok(). It only groups words that start with Space-Quotes and end with Quotes-Space
void split(char *argstring)
{
int _argc = 0;
char **_argv = malloc(sizeof(char*));
char *token;
int myFlag = 0;
for(token = strtok(argstring, " "); token != NULL; token = strtok(NULL, " "))
{
if (1 == myFlag)
{
//One of the previous token started with double quotes
if ('\"' == token[strlen(token)-1]) myFlag = 0; //This token ends with double quotes
_argv[_argc-1] = realloc(_argv[_argc-1], strlen(_argv[_argc-1]) + strlen(token) + 2); //Enlarge the previous token
strcat(_argv[_argc-1], " ");
strcat(_argv[_argc-1], token);
}
else
{
if ('\"' == token[0]) myFlag = 1; //This token starts with double quotes
_argv = realloc(_argv, (_argc + 1) * sizeof(char*)); //Add one element to the array of strings
_argv[_argc] = malloc(strlen(token) + 1); //Allocate the memory for the Nth element
strcpy(_argv[_argc], token); //Copy the token in the array
_argc++;
}
}
do
{
free(_argv[_argc--]);
} while (_argc >= 0);
}