For Programmers: Free Programming Magazines  


Home > Archive > C > June 2006 > Newbie help on string splitting









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Newbie help on string splitting
Smurff

2006-06-17, 8:01 am

Hi all,

I have a string with upto 20 ip addresses in seperated by ;

111.111.111.111;222.222.222.222;333.333.333.333

I am trying to get them into an array so I can compare to. This isnt
homework :) Im just trying to learn C and have given myself a small
project.

Any help would be appreciated.

Logically, I have started by trying to find a way of getting the
position of the first ;

char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333
/* Routine got from google groups */
int StrPos(const char *s, char c)
{
char *p;
p = strchr(s, c);
return (p) ? (p - s) : -1;
}


pos=StrPos(ipOneLine,';');

which returns 15, so what call can I use to say get a substring from 0
to 15 please?

Please be kind, I am still learning :)

Thanks
Smurff

Smurff

2006-06-17, 8:01 am

Ok, after a few hours Im nearly there

strtok

:)

regards





Smurff wrote:

> Hi all,
>
> I have a string with upto 20 ip addresses in seperated by ;
>
> 111.111.111.111;222.222.222.222;333.333.333.333
>
> I am trying to get them into an array so I can compare to. This isnt
> homework :) Im just trying to learn C and have given myself a small
> project.
>
> Any help would be appreciated.
>
> Logically, I have started by trying to find a way of getting the
> position of the first ;
>
> char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333
> /* Routine got from google groups */
> int StrPos(const char *s, char c)
> {
> char *p;
> p = strchr(s, c);
> return (p) ? (p - s) : -1;
> }
>
>
> pos=StrPos(ipOneLine,';');
>
> which returns 15, so what call can I use to say get a substring from 0
> to 15 please?
>
> Please be kind, I am still learning :)
>
> Thanks
> Smurff


Andrew Poelstra

2006-06-17, 8:01 am

On 2006-06-12, Smurff <danny.kellett@gmail.com> wrote:
> Hi all,
>
> I have a string with upto 20 ip addresses in seperated by ;
>
> 111.111.111.111;222.222.222.222;333.333.333.333
>

Basically, . separates octets, and ; separates addresses.

> I am trying to get them into an array so I can compare to. This isnt
> homework :) Im just trying to learn C and have given myself a small
> project.
>

Good for you. Good luck!

> Any help would be appreciated.
>
> Logically, I have started by trying to find a way of getting the
> position of the first ;
>

Actually, a logical first step would be to find out how to store the
addresses. You can use an unsigned int to store the first and second
halves of each address. Or, you can assume long int is 32 bits and
store the whole address in a variable. (There's a way using special C99
types like int_32fast or something, but I don't remember exactly what
they are called).

> char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333
> /* Routine got from google groups */
> int StrPos(const char *s, char c)
> {
> char *p;
> p = strchr(s, c);
> return (p) ? (p - s) : -1;
> }
>
>
> pos=StrPos(ipOneLine,';');
>


As you posted elsethread, strtok will help you out here.

> which returns 15, so what call can I use to say get a substring from 0
> to 15 please?
>

....

> Please be kind, I am still learning :)
>

Well, you not only used proper grammar and spelling, you posted your problem
clearly, indicated how urgently you needed the information, and asked for help
kindly. I'd say that you'll get far more helpful answers than one fellow who
insulted Keith Thompson for suggesting he bottom-post. ;-)

A few notes, in case you didn't know: Quote context, and add your reply below
the quotes. Clip signatures and unnecessary quotations.


To your problem, to store an individual IP, load it into an array of four chars
and shift them into a long (long isn't guarunteed to be 32 bits, so wait for a
more portable reply if you wish):

char cip [4] = {127, 0, 0, 1};
long lip;
int ctr;

for (ctr = 0; ctr < 4; ctr++)
{
lip = cip[ctr];
lip <<= 8;
}

How to get the address into an array is up to you; you appear to have found a
solution using strtok(), and I'd hate to interrupt that learning progress with
an answer key.

--
Andrew Poelstra < http://www.wpsoftware.net/blog >
To email me, use "apoelstra" at the above address.
I know that area of town like the back of my head.
CBFalconer

2006-06-17, 8:01 am

Smurff wrote:
>
> I have a string with upto 20 ip addresses in seperated by ;
>
> 111.111.111.111;222.222.222.222;333.333.333.333
>
> I am trying to get them into an array so I can compare to. This
> isnt homework :) Im just trying to learn C and have given myself
> a small project.
>
> Any help would be appreciated.


The following routine will do the extraction for you. Try it first
with TESTING defined on compilation, and then without for your own
use. With gcc you define it on the command line by: "gcc -DTESTING
toksplit.c"

/* ------- file toksplit.c ----------*/
#include "toksplit.h"

/* copy over the next token from an input string, after
skipping leading blanks (or other whitespace?). The
token is terminated by the first appearance of tokchar,
or by the end of the source string.

The caller must supply sufficient space in token to
receive any token, Otherwise tokens will be truncated.

Returns: a pointer past the terminating tokchar.

This will happily return an infinity of empty tokens if
called with src pointing to the end of a string. Tokens
will never include a copy of tokchar.

A better name would be "strtkn", except that is reserved
for the system namespace. Change to that at your risk.

released to Public Domain, by C.B. Falconer.
Published 2006-02-20. Attribution appreciated.
*/

const char *toksplit(const char *src, /* Source of tokens */
char tokchar, /* token delimiting char */
char *token, /* receiver of parsed token */
size_t lgh) /* length token can receive */
/* not including final '\0' */
{
if (src) {
while (' ' == *src) *src++;

while (*src && (tokchar != *src)) {
if (lgh) {
*token++ = *src;
--lgh;
}
src++;
}
if (*src && (tokchar == *src)) src++;
}
*token = '\0';
return src;
} /* toksplit */

#ifdef TESTING
#include <stdio.h>

#define ABRsize 6 /* length of acceptable token abbreviations */

int main(void)
{
char teststring[] = "This is a test, ,, abbrev, more";

const char *t, *s = teststring;
int i;
char token[ABRsize + 1];

puts(teststring);
t = s;
for (i = 0; i < 4; i++) {
t = toksplit(t, ',', token, ABRsize);
putchar(i + '1'); putchar(':');
puts(token);
}

puts("\nHow to detect 'no more tokens'");
t = s; i = 0;
while (*t) {
t = toksplit(t, ',', token, 3);
putchar(i + '1'); putchar(':');
puts(token);
i++;
}

puts("\nUsing blanks as token delimiters");
t = s; i = 0;
while (*t) {
t = toksplit(t, ' ', token, ABRsize);
putchar(i + '1'); putchar(':');
puts(token);
i++;
}
return 0;
} /* main */

#endif
/* ------- end file toksplit.c ----------*/

/* ------- file toksplit.h ----------*/
#ifndef H_toksplit_h
# define H_toksplit_h

# ifdef __cplusplus
extern "C" {
# endif

#include <stddef.h>

/* copy over the next token from an input string, after
skipping leading blanks (or other whitespace?). The
token is terminated by the first appearance of tokchar,
or by the end of the source string.

The caller must supply sufficient space in token to
receive any token, Otherwise tokens will be truncated.

Returns: a pointer past the terminating tokchar.

+ This will happily return an infinity of empty tokens if
called with src pointing to the end of a string. Tokens
will never include a copy of tokchar.

released to Public Domain, by C.B. Falconer.
Published 2006-02-20. Attribution appreciated.
*/

const char *toksplit(const char *src, /* Source of tokens */
char tokchar, /* token delimiting char */
char *token, /* receiver of parsed token */
size_t lgh); /* length token can receive */
/* not including final '\0' */

# ifdef __cplusplus
}
# endif
#endif
/* ------- end file toksplit.h ----------*/

--
Some useful references about C:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://www.eskimo.com/~scs/C-faq/top.html>
<http://benpfaff.org/writings/clc/off-topic.html>
<http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
<http://www.dinkumware.com/refxc.html> (C-library}
<http://gcc.gnu.org/onlinedocs/> (GNU docs)
<http://clc-wiki.net> (C-info)


CBFalconer

2006-06-17, 8:01 am

*** top-posting corrected ***
Smurff wrote:
> Smurff wrote:
>
.... snip ...[color=darkred]
>
> Ok, after a few hours Im nearly there
>
> strtok


Don't top-post. Your answer belongs after, or intermixed with, the
material to which you reply, after snipping irrelevant material.

strtok has the divantage of modifying the source string, and
being non-reentrant. My toksplit does not have these
divantages.

--
Some useful references about C:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://www.eskimo.com/~scs/C-faq/top.html>
<http://benpfaff.org/writings/clc/off-topic.html>
<http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
<http://www.dinkumware.com/refxc.html> (C-library}
<http://gcc.gnu.org/onlinedocs/> (GNU docs)
<http://clc-wiki.net> (C-info)

Smurff

2006-06-17, 8:01 am

Thank you for the kind words. Didnt know about "top posting".

Thanks again.
Smurff

Nelu

2006-06-17, 8:01 am

Smurff <danny.kellett@gmail.com> wrote:
> Thank you for the kind words. Didnt know about "top posting".

Now that you know about top-posting you should also know that
you should quote some relevant context when you post a
followup so whoever reads the post knows what you are talking about.
Not everybody can (or want to) lookup the previous message in thread.

From the original message:
> I have a string with upto 20 ip addresses in seperated by ;
>
> 111.111.111.111;222.222.222.222;333.333.333.333

Each component of an address fits in one octet. If the size of one
byte is at least 8 bits (1 octet) then it fits. That means you can use
a 32 bit unsigned integer to store one address. The only problem is that
you have to find that type in a portable manner unless your
compiler is C99 compliant, in which case you can always get the
types from <stdint.h>.
You could take each unsigned integer type and check the size of its
representation and create your own type that you can use throughout the
program to hold an address.

--
Ioan - Ciprian Tandau
tandau _at_ freeshell _dot_ org (hope it's not too late)
(... and that it still works...)
Barry Schwarz

2006-06-17, 8:01 am

On 12 Jun 2006 15:59:33 -0700, "Smurff" <danny.kellett@gmail.com>
wrote:

>Hi all,
>
>I have a string with upto 20 ip addresses in seperated by ;
>
>111.111.111.111;222.222.222.222;333.333.333.333
>
>I am trying to get them into an array so I can compare to. This isnt
>homework :) Im just trying to learn C and have given myself a small
>project.
>
>Any help would be appreciated.
>
>Logically, I have started by trying to find a way of getting the
>position of the first ;
>
>char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333


I assume the missing quotation marks and semicolon are just a typos.

>/* Routine got from google groups */
>int StrPos(const char *s, char c)
>{
> char *p;
> p = strchr(s, c);
> return (p) ? (p - s) : -1;
>}
>
>
>pos=StrPos(ipOneLine,';');
>
>which returns 15, so what call can I use to say get a substring from 0
>to 15 please?


Create a working char* (e.g., ptr).
Initialize it to point to the same place ipOneline points to.
Change your function call to
pos = StrPos(ptr, ';');
At some point between successive calls to the function, increment ptr
to point one beyond the semicolon just found, e.g.,
ptr += pos+1;


Remove del for email
Frederick Gotham

2006-06-17, 6:56 pm

Smurff posted:

> Hi all,
>
> I have a string with upto 20 ip addresses in seperated by ;
>
> 111.111.111.111;222.222.222.222;333.333.333.333
>
> I am trying to get them into an array so I can compare to.



I'd change the semi-colons to null characters, then make an array of
pointers to char's. Something like:

(Apologies for anything which isn't valid C... I come from a C++
background)


typedef struct TwentyIPs {

char *array[20];

} TwentyIPs;


TwentyIPs MakeArray( char *p )
{
TwentyIPs tips = { p };

char **current_str = tips.array + 1;

for ( ; *p; ++p )
{
if ( *p == ';' )
{
*p++ = 0;

*current_str++ = p;
}
}

return tips;
}

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
char buffer[] = "111.111.111.111;222.222.222.222;333.333.333.333";

TwentyIPs tips = MakeArray( buffer );


char **current_str = tips.array;


printf( "Original String: %s \n \n", buffer );


for( ; *current_str; ++current_str )
{
printf( "%s \n", *current_str );
}


system("PAUSE");
}


--

Frederick Gotham
Dave Thompson

2006-06-25, 9:56 pm

On Tue, 13 Jun 2006 03:06:32 GMT, Andrew Poelstra
<apoelstra@localhost.localdomain> wrote:

<snips>
[color=darkred]
>
> As you posted elsethread, strtok will help you out here.
>

Not if the argument points to a string literal (value) as here. If
it's read or moved into a writable buffer, strtok() is one choice.

<snip>
> To your problem, to store an individual IP, load it into an array of four chars
> and shift them into a long (long isn't guarunteed to be 32 bits, so wait for a
> more portable reply if you wish):
>
> char cip [4] = {127, 0, 0, 1};
> long lip;
> int ctr;
>
> for (ctr = 0; ctr < 4; ctr++)
> {
> lip = cip[ctr];
> lip <<= 8;
> }
>

long is guaranteed to be at least 32 bits, and long long at least 64.
But that includes the sign bit, and left shift into the sign bit isn't
standardly (portably) required to work, although most machines
nowadays are two's-complement where 'arithmetic' (signed) and
unsigned left shifts are actually the same. Even worse, plain char can
be and sometimes is signed, which will give you grossly wrong results.

It is 'int' that standardly guarantees only 16 bits, although many
platforms, probably most today, provide 32.

And if lip is an auto variable, i.e. within a function (block), you
need to initialize or assign it to 0 before starting the loop.

- David.Thompson1 at worldnet.att.net
websnarf@gmail.com

2006-06-26, 3:57 am

Smurff wrote:
> I have a string with upto 20 ip addresses in seperated by ;
>
> 111.111.111.111;222.222.222.222;333.333.333.333
>
> I am trying to get them into an array so I can compare to. This isnt
> homework :) Im just trying to learn C and have given myself a small
> project.
>
> Any help would be appreciated.
>
> Logically, I have started by trying to find a way of getting the
> position of the first ;
>
> char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333
> /* Routine got from google groups */
> int StrPos(const char *s, char c)
> {
> char *p;
> p = strchr(s, c);
> return (p) ? (p - s) : -1;
> }
>
> pos=StrPos(ipOneLine,';');
>
> which returns 15, so what call can I use to say get a substring from 0
> to 15 please?
>
> Please be kind, I am still learning :)


Well, when you finally figure it out, you are unlikely to be impressed.
If all you want to do is split a string into an array of strings split
by some token, you can do so with "The Better String Library" (
http://bstring.sf.net/ ) in fairly short code:

#include <stdio.h>
#include "bstrlib.h"

int ipEqStrIp (const bstring a0, const bstring a1) {
bstrlist l0 = bsplit (a0, '.'), l1 = bsplit (a1, '.');
int o0, o1, i, ret = 0;
if (l0 && l1 && l0->qty == l1->qty) {
for (ret = 1, i=0; i < i0->qty; i++) {
if (1 != sscanf(bdatae(a0->entry[i],"?"), "%d", &o0) ||
1 != sscanf(bdatae(a1->entry[i],"?"), "%d", &o1) ||
((o0 - o1) % 256) != 0) {
ret = 0;
break;
}
}
}
bstrListDestroy (l0);
bstrListDestroy (l1);
return ret;
}

int main () {
char *resp[2] = {"No", "Yes"};
struct tagbstring ipOneLine = bsStatic \
("111.111.111.111;222.222.222.222;333.333.333.333");
bstrList sl = bsplit (&ipOneLine, ';');
if (sl) {
printf ("%s == %s? %s\n", bdata (sl->entry[0]),
bdata (sl->entry[1]),
resp[ipEqStrIp (sl->entry[0], sl->entry[1])]);
bstrListDestroy (sl);
}
return 0;
}

Notice how short this code is; its fairly easy to understand and
basically *starts* with more useful starting primitives (like a split
function.)

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2009 codecomments.com