Hello, I'm trying to split a string into 4 separate strings using a delimiter "\n"

The initial string is:
"/usr/bin/ssh \n * \n 147.188.195.15, 147.188.193.15, 147.188.193.16 \n 22"

I would like it to be split up into four different char's so that

char *programnames = "/usr/bin/ssh \n"
char *uids = " * \n"
char *destips = "147.188.195.15, 147.188.193.15, 147.188.193.16 \n"
char *ports " 22"

Hopefully you should see the pattern I'm aiming for. The original string first starts off like "/usr/bin/ssh * 147.188.195.15, 147.188.193.15, 147.188.193.16 22" but i have to split it up using a BNF grammar where there are n number of spaces but no , before the space and I've done this by replacing the last space in n spaces with "\n". Thanks in advance.

Below is the code I have produced so far:

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

int main() {

    
    char *programnames;
    char *uids;
    char *destips;
    char *ports;
    

    char *result = "/usr/bin/ssh                    *   147.188.195.15,   147.188.193.15,       147.188.193.16       22";

    char src[200];
    strncpy(src, result, 200);
    int i = 0;
    while (i <= 200) {

        //clause to not new line if there was a , comma followed by n number of spaces
        if (((src[i] == ' ') && ((((src[(i - 1)] != ',') && (src[(i - 1)] != '\n')) && (src[(i - 1)] != ' ')) && (isalnum(src[(i + 1)]) || (src[(i + 1)] == '*'))))) {
            src[i] = '\n';
        }

        //clause to new line if there are n number of spaces between a letter, numer and *
        if (src[i] == ' ' && src[(i + 1)] == '*') {
            src[i] = '\n';
        }
        if (src[i] == '*' && src[(i + 1)] == ' ' && src[(i + 2)] == ' ') {
            src[i + 1] = '\n';
        }
        if (isdigit(src[i]) && src[(i + 1)] != ',' && src[(i + 2)] == ' ') {
            src[i + 1] = '\n';
        }
        src[i] = src[i];
        i++;
    }
    printf("LINE SPLIT RESULTS USING BNF GRAMMAR:\n %s", src);
    printf("\n");

    printf("TOKENS:\n");
    char basetokens[200];
    strncpy(basetokens, src, 200); //copy the result of the src into a basetokens to be processed into separate tokens

    char *tokens;
    tokens = strtok(basetokens, "\n");
    //printf(tokens);
   

    return 0;
}

Hello, I'm trying to split a string into 4 separate strings using a delimiter "\n"

i would suggest that replacing printable characters with '\n' as a delimiter is a Bad Idea. Because what is '\n', anyhow?

is it 0x0D ?
is it 0x0A ?
or is it 0x0D + 0x0A ?

rethink the problem and just parse your tokens on what actually exists without overwriting. if you must overwrite, then at least use another printable character.


.

Edited 6 Years Ago by jephthah: n/a

Yea i know that is horrible way to do that part i wanted, however it took me 4 hours just to get that far as i've only just started to learn C, so atm i'm not worried about that as it does what i need, unless you know how to split that in the first place by N number of spaces as long as there isn't a "," before it.

An idea:

#include <stdio.h>

int main()
{
   char result[] = "/usr/bin/ssh \n"
                   " * \n"
                   " 147.188.195.15, 147.188.193.15, 147.188.193.16 \n"
                   " 22";
   char programnames[256], uids[256], destips[256], ports[256];
   if ( sscanf(result, "%255[^\n] %255[^\n] %255[^\n] %255[^\n]",
               programnames, uids, destips, ports) == 4 )
   {
      printf("programnames = \"%s\"\n", programnames);
      printf("uids         = \"%s\"\n", uids);
      printf("destips      = \"%s\"\n", destips);
      printf("ports        = \"%s\"\n", ports);
   }
   return 0;
}

/* my output
programnames = "/usr/bin/ssh "
uids         = "* "
destips      = "147.188.195.15, 147.188.193.15, 147.188.193.16 "
ports        = "22"
*/

i'm still saying that overwriting the original string with \newline characters is a bad idea. it makes the program unnecessarily complicated, and opens up more opportunities for buggy code.

I suggest that you reconsider your approach to the problem. to put it one way, i think you are "going around your ass to get to your elbow". nothing personal, its a problem all new programmers (and some old) have.

consider this: simply break your string into tokens that are already delimited by the existing spaces. then, concatenate all IP addresses (with or without their trailing commas) into one string.

const char str = "/usr/bin/ssh * 147.188.195.15, 147.188.193.15, 147.188.193.16 22";

char PathName[MAXPATHSIZE] = '\0';
char UID[MAXUIDSIZE] = '\0';
char IPaddr[MAXIPADDRSIZE] = '\0';
char Port[MAXPORTSIZE] = '\0';

char *ptr;

ptr = strtok(str," ");
while (ptr != NULL)
{
   if (strstr( ptr, "/") != 0)
      strcpy (PathName, ptr);
   else if (strstr( ptr, ".") != 0)
      strcat (IPaddr, ptr);
   else if (strstr( ptr, "*") != 0)
      strcpy (UID, ptr);

   /*
   ...  now you figure out how to distinguish between numeric UIDs 
   ...  and numeric Port Numbers
   ...  One possibility is a "state machine" or just a flag that tracks when 
   ...  the IPaddresses have been found, so a subsequent
   ...  simple numeric must be a Port and not a UID.
   ...*/

   ptr = strtok(NULL, " ");
}

.

Edited 6 Years Ago by jephthah: n/a

To Dave Sinkula,
Thank you very much that was a very nice and efficient way to solve my problem.

To Jephthah,
I completely agree with you and understand where your coming from however i've spent so long trying to do a fraction of my whole program and I was getting tired and frustrated as I know I could have finished the whole thing in like an hour or two if I was doing it in Java which i'm used to programming in. Therefore, I just want to get a basic working version that I can fine tune afterwards and your input will be very useful for that.

I'll mark this thread as solved for now as there is an answer to my initial problem and hopefully somebody else will have use for this aswell one day.

This question has already been answered. Start a new discussion instead.