0

I'm a beginner at C and I'm stuck on a simple problem. Here it goes:
I have a string formatted like this: "first1:second1\nsecond2\nfirst3:second3" ... and so on.
As you can see from the the example the first field is optional ([firstx:]secondx).
I need to get a resulting string which contains only the second field. Like this: "second1\nsecond2\nsecond3".

I did some research here on stack (string splitting in C) and I found that there are two main functions in C for string splitting: strtok (obsolete) and strsep.
I tried to write the code using both functions (plus strdup) without success. Most of the time I get some unpredictable result.

Better ideas?
Thanks in advance

EDIT:
This was my first try

int main(int argc, char** argv){
    char * stri = "ciao:come\nva\nquialla:grande\n";
    char * strcopy = strdup(stri); // since strsep and strtok both modify the input string
    char * token;
    while((token = strsep(&strcopy, "\n"))){
        if(token[0] != '\0'){ // I don't want the last match of '\n'
            char * sub_copy = strdup(token);
            char * sub_token = strtok(sub_copy, ":");
            sub_token = strtok(NULL, ":");
            if(sub_token[0] != '\0'){
                printf("%s\n", sub_token);
            }
        }
        free(sub_copy);
    }
    free(strcopy);
}

Expected output: "come", "si", "grande"

Mr. Blue
  • 75
  • 2
  • 8
  • 1
    Show us your code. `strtok()` is not obsolete! – John Zwinck Jun 03 '17 at 09:40
  • @JohnZwinck It should be :p, `strtok_r()` is far better. – Stargateur Jun 03 '17 at 09:42
  • 1
    @Stargateur: Better yet: `strspn()` / `strcspn()`. – EOF Jun 03 '17 at 09:55
  • when the parameters to the `main()` function are not used, then use the signature: `int main( void )` – user3629249 Jun 04 '17 at 03:07
  • when calling `strdup()`, always check (!=NULL) the returned value to assure the operation was successful – user3629249 Jun 04 '17 at 03:08
  • the posted code, even after adding statements for: 'stdio.h', 'stdlib.h' and 'string.h' does not compile. One reason is this statement: `free(sub_copy);` as the pointer: `sub_copy` is only visible with the scope of the code block: `if(token[0] != '\0')` – user3629249 Jun 04 '17 at 03:13
  • regarding: `while((token = strsep(&strcopy, "\n"))){` before searching for a newline, should be checking for an (optional) 'xxx:' sequence – user3629249 Jun 04 '17 at 03:16
  • regarding: `if(sub_token[0] != '\0')` the first char will NEVER be '\0'. However, the contents of `sub_token` could be NULL. – user3629249 Jun 04 '17 at 03:19

1 Answers1

2

Here's a solution with strcspn:

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

int main(void) {
    const char *str = "ciao:come\nva\nquialla:grande\n";
    const char *p = str;
    while (*p) {
        size_t n = strcspn(p, ":\n");
        if (p[n] == ':') {
            p += n + 1;
            n = strcspn(p , "\n");
        }
        if (p[n] == '\n') {
            n++;
        }
        fwrite(p, 1, n, stdout);
        p += n;
    }
    return 0;
}

We compute the size of the initial segment not containing : or \n. If it's followed by a :, we skip over it and get the next segment that doesn't contain \n.

If it's followed by \n, we include the newline character in the segment. Then we just need to output the current segment and update p to continue processing the rest of the string in the same way.

We stop when *p is '\0', i.e. when the end of the string is reached.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • @Stargateur I don't understand that comment. Your suggested replacement still outputs `\n`. – melpomene Jun 03 '17 at 10:29
  • That I wanted to say is that your example is not really easy to understand, the OP probably wants the token to be a "separate string". Here you print it without removing the original `'\n'` of the string. Maybe this will be better to do this for example of course http://rextester.com/BLS46506. But anyway, never mind, forget it. – Stargateur Jun 03 '17 at 10:40