I have written the following code to split the lines, in which the strings are separated by symbol '#', and storing in the array named as'buf' here. This code is working fine if I am comparing any string present in the array[0] . but If I try to find the string present in array[3] for example here as 'admin', then it is having error as 'segmentation fault' . Could anyone help me to find why this code is not comparing any other argument.
I would be very thankful for this.
char **strsplit(const char* str, const char* delim, size_t* numtokens) {
char *s = strdup(str);
size_t tokens_alloc = 1;
size_t tokens_used = 0;
char **tokens = calloc(tokens_alloc, sizeof(char*));
char *token, *rest = s;
while ((token = strsep(&rest, delim)) != NULL) {
if (tokens_used == tokens_alloc) {
tokens_alloc *= 2;
tokens = realloc(tokens, tokens_alloc * sizeof(char*));
}
tokens[tokens_used++] = strdup(token);
}
if (tokens_used == 0) {
free(tokens);
tokens = NULL;
} else {
tokens = realloc(tokens, tokens_used * sizeof(char*));
}
*numtokens = tokens_used;
free(s);
return tokens;
}
The main() is as follows:
int main(void) {
char *line = NULL;
size_t linelen;
char **tokens;
size_t numtokens;
int ret=1;
FILE *ptr_file;
char buf[1000];
system("rm -rf input1.txt");
system("/www/stest/mds1 > input1.txt");
ptr_file =fopen("/www/stest/input1.txt","r");
if (!ptr_file)
return 1;
while (fgets(buf,1000, ptr_file)!=NULL)
{
tokens = strsplit(buf, "#\n", &numtokens);
size_t i;
for ( i = 0; i < numtokens; i++)
{
ret=strcmp(tokens[3],"member");
if(ret==0)
{
printf("%s",buf);
break;
}
}
fclose(ptr_file);
return 0;
return EXIT_SUCCESS;
}
Here is the output of the above code and I am having error if I want to print the lines which has 'member'as the third argument of the array.
abc#google.com#abdu#admin
abc#rediff.com#savya#cashier
abc#yahoo.com.com#andy#member
abc#google.com#susan#group
abc#facebook.com#andre#admin
Thanks.
I suspect what you want is something like this:
tokens = strsplit(buf, "#\n", &numtokens);
if(numtokens >= 4 && strcmp(tokens[3],"member") == 0)
{
printf("%s",buf);
}
As shown in George Houpis's answer it would also be good to double-check that strsplit does not return a null pointer.
This is not an answer, but the comment is not big enough. If you run this as your main, what is the output?
int main( int argc, char ** argv )
{
FILE * fin = fopen( "/www/stest/input1.txt", "rt" );
if( !fin )
return 1;
char buffer[1000];
while( fgets( buffer, 1000, fin ) )
{
size_t token_count;
char ** tokens = strsplit( buffer, "#\n", &token_count );
if( tokens )
{
size_t index;
for( index = 0; index < token_count; ++index )
if( !strcmp( tokens[index], "member" ) )
printf( "%d: %s | %s", index, tokens[index], buffer );
for( index = 0; index < token_count; ++index )
free( tokens[index] );
free( tokens );
}
}
fclose( fin );
return 0;
}
When I run with those 5 lines in the text file, I get:
3: member | abc#yahoo.com.com#andy#member
EDIT:
You can tokenize the string without malloc by keeping a second buffer and using pointers to that (still uses memory on the stack).
int main( int argc, char ** argv )
{
FILE * fin = fopen( argv[1], "rt" );
if( !fin )
return 1;
char buffer[1000];
while( fgets( buffer, 1000, fin ) )
{
char buffer_copy[1000];
strcpy( buffer_copy, buffer );
char * tokens[1000];
size_t token_count = 0;
char * ptr = tokens[token_count] = buffer_copy;
while( *ptr )
if( ( *ptr == '#' ) || ( *ptr == '\n' ) )
*ptr++ = '\0', tokens[++token_count] = ptr;
else
++ptr;
size_t index;
for( index = 0; index < token_count; ++index )
if( !strcmp( tokens[index], "member" ) )
printf( "%d: %s | %s", index, tokens[index], buffer );
}
fclose( fin );
return 0;
}
If you go with fixed position (always 3rd (0 indexed)), you can just scan and check:
int is_member( const char * buffer )
{
if( !buffer )
return 0;
size_t index;
const char * ptr = buffer;
for( index = 0; index < 3; ++index, ++ptr )
if( !( ptr = strchr( ptr, '#' ) ) )
return 0;
return !strncmp( ptr, "member", 6 ) && ( ( *( ptr + 7 ) == 0 ) || ( *( ptr + 7 ) == '#' ) || ( *( ptr + 7 ) == '\n' ) );
}
int main( int argc, char ** argv )
{
FILE * fin = fopen( argv[1], "rt" );
if( !fin )
return 1;
char buffer[1000];
while( fgets( buffer, 1000, fin ) )
if( is_member( buffer ) )
printf( "%s", buffer );
fclose( fin );
return 0;
}
Or if the position is not known, then you can find each token on the fly. This takes no significant additional memory (a couple pointers) and does not modify your buffer:
int is_member( const char * buffer, const char * delimiters )
{
size_t index;
const char * ptr = buffer, * eptr = buffer;
for( ; eptr; ptr = eptr + 1 )
// If the next delimiter is found and it is 6 characters away or not found, and the substring matches 'member', return 1.
if( ( !( eptr = strpbrk( ptr, delimiters ) ) || ( eptr - ptr == 6 ) ) &&
!strncmp( ptr, "member", 6 ) )
return 1;
return 0;
}
int main( int argc, char ** argv )
{
FILE * fin = fopen( argv[1], "rt" );
if( !fin )
return 1;
char buffer[1000];
while( fgets( buffer, 1000, fin ) )
if( is_member( buffer, "#\n" ) )
printf( "%s", buffer );
fclose( fin );
return 0;
}
I did it it without using file * since I have the buffer already. It is working. thanks.
char buffer_copy[1000];
strcpy( buffer_copy, buffer );
char * tokens[1000];
size_t token_count = 0;
char * ptr = tokens[token_count] = buffer_copy;
while( *ptr )
if( ( *ptr == '#' ) || ( *ptr == '\n' ) )
*ptr++ = '\0', tokens[++token_count] = ptr;
else
++ptr;
size_t index;
for( index = 0; index < token_count; ++index )
if( !strcmp( tokens[index], "member" ) )
printf( "%d: %s | %s", index, tokens[index], buffer );
Related
Let's say I have this string:
char *myTestString = "Hello AND test AND test2";
I want to break this down into the set { Hello, test, test2 }, which I can finally iterate over.
Or I have
char *myTestString2 = "Hi AND there AND test AND test2";
I want to break this down into the set { Hi, there, test, test2 }, which I can later iterate over.
How do I achieve this using C?
EDIT:
Another example is splitting "Hello there AND test" should give out set { Hello there, test }.
For clarification "AND" is delimiter here.
When code does not want to alter the source string, use strcspn(s, delimet) to look for initial portion of a s not make up of delimit. It returns the offset.
Use strspn(s, delimet) to look for initial portion of a s made up of delimit. It returns the offset.
Note: As others mentioned, strtok() is no good for string literals, and in this case you should go with Chux's answer (strcspn), but if that's not an issue and you can work with strings stored in arrays, then continue reading. A last resort effort would be to work with a copy of the string literal.
First, you have to decide which data structure you'll use for your set (e.g. a simple linked list, where you check before instertion for duplicates).
Then, use strtok() to your string, and if the current token is different than "AND" (or any other string to be ignored - you'd have an ignore set of strings as well), then insert it in the set, otherwise, continue to the next token.
Here is a basic Complete Minimal Example to get you started:
#include <stdio.h>
#include <string.h>
#define N 3 // Max size of set
#define LEN 32 // Max length of word - 1
int main ()
{
char set[N][LEN] = {0};
char* ignore_str = "AND";
char str[] ="Hello AND test AND test2";
char* pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ");
int i = 0;
while (pch != NULL)
{
printf ("%s\n",pch);
if(strcmp(pch, ignore_str))
strcpy(set[i++], pch);
pch = strtok (NULL, " ");
}
printf("My set is: {");
for(int j = 0; j < i; ++j)
printf("%s, ", set[j]);
printf("}\n");
return 0;
}
Output:
Splitting string "Hello AND test AND test2" into tokens:
Hello
AND
test
AND
test2
My set is: {Hello, test, test2, }
Here, I used an array to represent the set, assuming that the maximum size of the set would be 3. Of course, you could use more dynamic approach instead (e.g. dynamic memory allocated array or list).
Here you are.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ** split( const char *s1, const char *s2 )
{
char **tokens = malloc( sizeof( char * ) );
int success = tokens != NULL;
if ( success )
{
const char *delim = " \t";
*tokens = NULL;
for ( size_t n = 1, len = strlen( s2 ); success && *s1; )
{
s1 += strspn( s1, delim );
if ( *s1 )
{
const char *p = s1;
s1 += strcspn( s1, delim );
if ( strncmp( p, s2, len ) != 0 )
{
char **tmp = realloc( tokens, ( n + 1 ) * sizeof( char * ) );
if ( ( success = tmp != NULL ) )
{
tokens = tmp;
success = ( tokens[n-1] = calloc( 1, s1 - p + 1 ) ) != NULL;
strncpy( tokens[n-1], p, s1 - p );
tokens[n] = NULL;
++n;
}
if ( !success )
{
for ( size_t i = 0; i < n; i++ ) free( tokens[i] );
free( tokens );
}
}
}
}
}
return tokens;
}
int main(void)
{
const char *s1 = "Hi AND there AND test AND test2";
const char *s2 = "AND";
char **tokens = split( s1, s2 );
if ( tokens != NULL )
{
for ( char **p = tokens; *p != NULL; ++p )
{
puts( *p );
}
char **p = tokens;
do
{
free( *p );
} while ( *p++ != NULL );
free( tokens );
}
return 0;
}
The program output is
Hi
there
test
test2
The function returns NULL if a memory allocation was not successful. Otherwise it returns a pointer to an array of the element type char * the last element of which is null pointer.
The words in the source string are splited by tabs and spaces. You can change the delimiters as you like.
After your comment to my previous solution it seems you need the following
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ** split( const char *s1, const char *s2 )
{
char **tokens = malloc( sizeof( char * ) );
int success = tokens != NULL;
if ( success )
{
const char *delim = " \t";
*tokens = NULL;
for ( size_t n = 1, len2 = strlen( s2 ); success && *s1; )
{
for ( int empty = 1; empty; )
{
s1 += strspn( s1, delim );
if ( ( empty = strncmp( s1, s2, len2 ) == 0 ) )
{
s1 += len2;
}
}
if ( *s1 )
{
const char *p = strstr( s1, s2 );
size_t len1 = p == NULL ? strlen( s1 ) : p - s1;
char **tmp = realloc( tokens, ( n + 1 ) * sizeof( char * ) );
if ( ( success = tmp != NULL ) )
{
tokens = tmp;
success = ( tokens[n-1] = calloc( 1, len1 + 1 ) ) != NULL;
strncpy( tokens[n-1], s1, len1 );
tokens[n] = NULL;
++n;
s1 += p == NULL ? len1 : len1 + len2;
}
if ( !success )
{
for ( size_t i = 0; i < n; i++ ) free( tokens[i] );
free( tokens );
}
}
}
}
return tokens;
}
int main(void)
{
const char *s1 = "Hi there AND test test2";
const char *s2 = "AND";
char **tokens = split( s1, s2 );
if ( tokens != NULL )
{
for ( char **p = tokens; *p != NULL; ++p )
{
puts( *p );
}
char **p = tokens;
do
{
free( *p );
} while ( *p++ != NULL );
free( tokens );
}
return 0;
}
The program output is
Hi there
test test2
Maybe you need also to remove trailing blanks of a extracted sub-string that I hope you can do yourself.:).
strstr can be used to locate the sub-string. Check that the leading and trailing characters are space or trailing terminating zero.
As needed remove whitespace.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main ( void) {
char *myTestString = " AND SANDY AND Hello there AND AND test AND test2 AND test3 ";
char *match = "AND";
char *first = myTestString;
char *start = myTestString;
char *find = myTestString;
int len = strlen ( match);
while ( isspace ( (unsigned char)*start)) {//skip leading whitespace
++start;
++first;
}
while ( ( find = strstr ( start, match))) {
if ( find != first) {
//check for leading and trailing space or terminating zero
while ( ! (isspace ( (unsigned char)*(find - 1))
&& ( isspace ( (unsigned char)*(find + len)) || 0 == *(find + len)))) {
find = strstr ( find + 1, match);
if ( ! find) {
find = start + strlen ( start);
while ( isspace ( (unsigned char)*(find - 1))) {
--find;
}
break;
}
}
int span = (int)(find - start);
if ( span) {
printf ( "%.*s\n", span, start);
}
}
start = find + strlen ( match);
while ( isspace ( (unsigned char)*start)) {//skip trailing whitespace
++start;
}
}
if ( *start) {
int end = strlen ( start) - 1;
while ( isspace ( (unsigned char)start[end])) {
--end;//remove trailing whitspace
}
printf ("%.*s\n", end + 1, start);
}
return 0;
}
Allocate memory to char**, allocate memory and copy each token.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char **freetokens ( char **tokens);
void showtokens ( char **tokens);
char **addtoken ( char **tokens, int *count, char *text, int size);
int main ( void) {
char *myTestString = " AND SANDY AND Hello there test AND AND test2 AND test3 ";
char *match = "AND";
char *first = myTestString;
char *start = myTestString;
char *find = myTestString;
char **tokens = NULL;
int items = 0;
int len = strlen ( match);
while ( isspace ( (unsigned char)*start)) {//skip leading whitespace
++start;
++first;
}
while ( ( find = strstr ( start, match))) {
if ( find != first) {
//check for leading and trailing space or terminating zero
while ( ! (isspace ( (unsigned char)*(find - 1))
&& ( isspace ( (unsigned char)*(find + len)) || 0 == *(find + len)))) {
find = strstr ( find + 1, match);
if ( ! find) {
find = start + strlen ( start);
while ( isspace ( (unsigned char)*(find - 1))) {
--find;//remove trailing whitespace
}
break;
}
}
int span = (int)(find - start);
if ( span) {
tokens = addtoken ( tokens, &items, start, span);
}
}
start = find + strlen ( match);
while ( isspace ( (unsigned char)*start)) {//skip trailing whitespace
++start;
}
}
if ( *start) {
int end = strlen ( start);
while ( isspace ( (unsigned char)start[end - 1])) {
--end;
}
tokens = addtoken ( tokens, &items, start, end);
}
showtokens ( tokens);
tokens = freetokens ( tokens);
return 0;
}
char **addtoken ( char **tokens, int *count, char *text, int size) {
char **temp = NULL;
if ( NULL == ( temp = realloc ( tokens, sizeof *tokens * ( *count + 2)))) {
fprintf ( stderr, "problem realloc tokens\n");
return tokens;
}
tokens = temp;
tokens[*count + 1] = NULL;//sentinel
if ( NULL == ( tokens[*count] = malloc ( size + 1))) {
fprintf ( stderr, "problem realloc tokens[]\n");
return tokens;
}
memmove ( tokens[*count], text, size);
tokens[*count][size] = 0;//terminate
++*count;
return tokens;
}
char **freetokens ( char **tokens) {
int each = 0;
while ( tokens && tokens[each]) {
free ( tokens[each]);
++each;
}
free ( tokens);
return NULL;
}
strstr() is the tool you are looking for. It can locate a string inside another string.
Here is a simple solution with these extra specifications:
the return value is an array of (n+1) entries, the last one being a null pointer.
the separator string can appear anywhere, including inside a word.
substrings are trimmed: initial and trailing white space is removed
substrings are allocated with strndup() which is standardized in POSIX.
the separator string must have a length of at least 1
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup_trim(const char *s, size_t n) {
while (n > 0 && isspace((unsigned char)*s)) {
s++;
n--;
}
while (n > 0 && isspace((unsigned char)s[n - 1])) {
n--;
}
return strndup(s, n);
}
char **split(const char *str, const char *sep) {
size_t i, n, sep_len = strlen(sep);
char **a;
const char *p, *p0;
if (sep_len == 0)
return NULL;
for (n = 0, p = str; (p = strstr(p, sep)) != NULL; n++, p += sep_len)
continue;
a = malloc(sizeof(*a) * (n + 2));
if (a == NULL)
return NULL;
for (i = 0, p = str; (p = strstr(p0 = p, sep)) != NULL; i++, p += sep_len) {
a[i] = strdup_trim(p0, p - p0);
}
a[i++] = strdup_trim(p0, strlen(p0));
a[i] = NULL;
return a;
}
void free_split(char **a) {
if (a) {
for (size_t i = 0; a[i]; i++)
free(a[i]);
free(a);
}
}
void test(const char *str, const char *sep) {
char **a = split(str, sep);
printf("split('%s', '%s') -> {", str, sep);
for (size_t i = 0; a[i]; i++)
printf("%s '%s'", &","[!i], a[i]);
printf(" }\n");
free_split(a);
}
int main() {
test("Hello AND test AND test2", "AND");
test("Hi AND there AND test AND test2", "AND");
test("Hello there AND test", "AND");
return 0;
}
Output:
split('Hello AND test AND test2', 'AND') -> { 'Hello', 'test', 'test2' }
split('Hi AND there AND test AND test2', 'AND') -> { 'Hi', 'there', 'test', 'test2' }
split('Hello there AND test', 'AND') -> { 'Hello there', 'test' }
This question is really close to this to this topic but I prefer the lisibility and the pointers clarification I needed offered by this solution.
So I've got a data file and I get a very long array of char from it. I want to split this string into an array with, in each case, a string wich correspond to a line of this file.
I saw solutions but they all use limited arrays, since I don't know the lenght of each line, I really need to allocate all of them dynamicly but I can't find the lenght of the lines because strtokdoesn't put a null character \0at the end of each string.
What I've got for now is this two solutions but neither work:
int get_lines(char *file, char **lines) {
int nb_lines = 0;
char *token = strtok(file, "\n");
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, "\n");
nb_lines = i;
}
nb_lines++;
lines = malloc((nb_lines + 1) * sizeof(char*));
lines[nb_lines] = '\0';
token = strtok(file, "\n");
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, "\n");
int nb_char = 0;
for(int j = 0; token[j] != '\n'; j++) //This will cause SIGSEGV because strtok don't keep the '\n' at the end
nb_char = j;
nb_char++;
token[nb_char] = '\0'; //This cause SIGSEGV because token's allocation finish at [nb_char-1]
lines[i] = malloc(strlen(token) * sizeof(char)); //strlen cause SIGSEGV because I cannot place the '\0' at the end of token
printf("%s", token); //SIGSEGV because printf don't find the '\0'
lines[i] = token;
}
for(int i = 0; i < nb_lines; i++) {
printf("%s", lines[i]); //SIGSEGV
}
return nb_lines;
}
So you can see above the idea of what I want to do and why it doesn't work.
Below you will see an other try I made but I'm stuck at the same point:
int count_subtrings(char* string, char* separator) {
int nb_lines = 0;
char *token = strtok(string, separator);
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, separator);
nb_lines = i;
}
return nb_lines + 1;
}
char** split_string(char* string, char* separator) {
char **sub_strings = malloc((count_subtrings(string, separator) + 1) * sizeof(char*));
for(int i = 0; string[i] != EOF; i++) {
//How to get the string[i] lenght to malloc them ?
}
}
My file is quite big and the lines can be too so I don't want to malloc an other table with a size of (strlen(file) + 1) * sizeof(char) to be sure each line won't SIGSEGV and I also find this solution quite dirty, if you guys had an other idea, I would be really happy.
(Sorry for the english mistakes, I'm not really good)
Your approach with strtok has two drawbacks: First, strtok modifies the string,so you can only pass the original string once. Second, it skips empty lines, because it tretas stretches of nelines as a single token separator.. (I don't know ehether that is a concern to you.)
You can countthe newlines with a single pass through the string. Allocate memory for your line array and make a second pass, where you split the string at newlines:
char **splitlines(char *msg)
{
char **line;
char *prev = msg;
char *p = msg;
size_t count = 0;
size_t n;
while (*p) {
if (*p== '\n') count++;
p++;
}
line = malloc((count + 2) * sizeof(*line));
if (line == NULL) return NULL;
p = msg;
n = 0;
while (*p) {
if (*p == '\n') {
line[n++] = prev;
*p = '\0';
prev = p + 1;
}
p++;
}
if (*prev) line[n++] = prev;
line[n++] = NULL;
return line;
}
I've allocated two more line pointers than the newlines count: One for the case that the last line doesn't end with a newline and another one to place a NULL sentinel at the end, so that you know where yourarray ends. (You could, of course, return the actual line count via a pointer to a size_t.)
the following proposed code:
cleanly compiles
(within the limits of the heap size) doesn't care about the input file size
echo's the resulting array of file lines, double spaced, just to show it worked. for single spacing, replace the puts() with printf()
and now the code
#include <stdio.h> // getline(), perror(), fopen(), fclose()
#include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free()
int main( void )
{
FILE *fp = fopen( "untitled1.c", "r" );
if( !fp )
{
perror( "fopen for reading untitled1.c failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char **lines = NULL;
size_t availableLines = 0;
size_t usedLines = 0;
char *line = NULL;
size_t lineLen = 0;
while( -1 != getline( &line, &lineLen, fp ) )
{
if( usedLines >= availableLines )
{
availableLines = (availableLines)? availableLines*2 : 1;
char **temp = realloc( lines, sizeof( char* ) * availableLines );
if( !temp )
{
perror( "realloc failed" );
free( lines );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else realloc successful
lines = temp;
}
lines[ usedLines ] = line;
usedLines++;
line = NULL;
lineLen = 0;
}
fclose( fp );
for( size_t i = 0; i<usedLines; i++ )
{
puts( lines[i] );
}
free( lines );
}
Given the above code is in a file named: untitled1.c the following is the output.
#include <stdio.h> // getline(), perror(), fopen(), fclose()
#include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free()
int main( void )
{
FILE *fp = fopen( "untitled1.c", "r" );
if( !fp )
{
perror( "fopen for reading untitled1.c failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char **lines = NULL;
size_t availableLines = 0;
size_t usedLines = 0;
char *line = NULL;
size_t lineLen = 0;
while( -1 != getline( &line, &lineLen, fp ) )
{
if( usedLines >= availableLines )
{
availableLines = (availableLines)? availableLines*2 : 1;
char **temp = realloc( lines, sizeof( char* ) * availableLines );
if( !temp )
{
perror( "realloc failed" );
free( lines );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else realloc successful
lines = temp;
}
lines[ usedLines ] = line;
usedLines++;
line = NULL;
lineLen = 0;
}
fclose( fp );
for( size_t i = 0; i<usedLines; i++ )
{
puts( lines[i] );
}
free( lines );
}
I can successfully show the text's words.
But I can't alphabetically sort.
How to text's words inset to character myArray = (char)malloc (size);
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static int compare (const void * a, const void * b);
int main(int argc, char *argv[])
{
FILE *fp;
char ch;
int size = 0;
fp = fopen("data.txt", "r");
if (fp == NULL)
printf("\nFile unable to open ");
else
printf("\nFile opened ");
fseek(fp, 0, 2); /* file pointer at the end of file */
size = ftell(fp); /* take a position of file pointer un size variable */
//char *myArray = (char*)malloc(size * sizeof *myArray);
char *myArray = (char*)malloc(size);
static const char filename[] = "data.txt";
FILE *file = fopen(filename, "r");
if ( file != NULL ){
int ch, word = 0, index= 0,index2 = 0;
while ( (ch = fgetc(file)) != EOF ){
if ( isspace(ch) || ispunct(ch) ){
if ( word ){
word = 0;
myArray[index++] = '\n';
//putchar('\n');
}
}else{
word = 1;
//putchar(ch);
myArray[index++] = ch;
index2++;
}
}
printf("%s", myArray);
fclose(file);
int i;
for(i = 0;i < sizeof(myArray);i++){
putchar(myArray[i]);
}
//qsort (array, 2, sizeof (const char *), compare);
//for (int i = 0; i < 2; i++) {
// printf ("%d: %s.\n", i, array[i]);
//}
}
}
static int compare (const void * a, const void * b)
{
return strcmp (*(const char **) a, *(const char **) b);
}
The qsort() call wants an array of pointers to character strings. So you would need to organize your words that way. For example:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char myArray[] = "This\nis\na\nsample\ntext\nstring\nas\nthough\nfrom\nyour\nfile";
char **myWords;
//
// Compare two strings case insensitive
//
static int compare (const void * a, const void * b)
{
char *aStr, *bStr;
int i, retVal;
if ( !( aStr = strdup( *(const char **) a ) ) )
return 1;
if ( !( bStr = strdup( *(const char **) b ) ) ) {
free( aStr );
return -1;
}
for ( i=0; i<strlen( aStr ); i++ )
aStr[i] = (char)tolower( (int)aStr[i] );
for ( i=0; i<strlen( bStr ); i++ )
bStr[i] = (char)tolower( (int)bStr[i] );
retVal = strcmp( aStr, bStr );
free( aStr );
free( bStr );
return retVal;
}
int main ()
{
char *curWord, *nextWord;
long wordCount;
int i;
//
// myArray contains an array of newline delimited words as
// you have in your code after reading from the file
//
for ( i=0; i<strlen(myArray); i++ )
putchar( myArray[i] );
//
// If myArray is empty then no need to sort
//
if ( strlen( myArray ) == 0 ) {
printf( "Nothing to sort\n" );
return 0;
}
//
// Count how many newlines are in myArray - assume at least one
//
for ( wordCount=1, nextWord=myArray;
( nextWord = strchr( nextWord, (int)'\n' ) );
wordCount++, nextWord++ );
//
// If only one word then no need to sort
//
if ( wordCount == 1 ) {
printf ("\n0: %s.\n", myArray );
return 0;
}
//
// Allocate enough space to hold a new copy of each word
//
if ( !( myWords = calloc( wordCount, sizeof(char *) ) ) )
return 1;
//
// Load words from myArray into myWords
//
curWord = nextWord = myArray;
i = 0;
while ( ( nextWord = strchr( nextWord, (int)'\n' ) ) ) {
*nextWord++ = '\0';
myWords[i] = strdup( curWord );
if ( !myWords[i] ) {
printf( "\nFile too big for memory\n" );
return 1;
}
i++;
curWord = nextWord;
}
myWords[i] = curWord;
//
// Sort the array of words in myWords
//
qsort( myWords, wordCount, sizeof(char *), compare );
//
// Dump out sorted array
//
printf( "\n" );
for( i = 0; i < wordCount; i++ )
printf( "%d: %s.\n", i, myWords[i] );
//
// Free your memory here - but since exiting main() and
// program is ending no need to worry about it.
//
return 0;
}
I have a table with 6 columns and i have CSV Export like this with 6 entries per Line
me;val1;val2;val3;val4;val5;
me;val1;val2;val3;val4;val5;
I need to read these entries and Insert it into the SQLITE3 Database.So inorder to parse the CSV I use
void readcsv()
{
FILE* stream = fopen("input.csv", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp = strdup(line);
printf("Field 3 would be %s\n", getcsvfield(tmp, 3));
// NOTE strtok clobbers tmp
free(tmp);
}
}
//Used for parsing CSV
const char* getcsvfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ";");
tok && *tok;
tok = strtok(NULL, ";\n"))
{
if (!--num)
return tok;
}
return NULL;
}
So will i have to call getcsvfield(tmp, fieldnumber) again and again in the Insert Query like this or is there a cleaner and efficient way.
execute("INSERT INTO table(a,b,c,d,e,f) VALUES('%s','%s','%s');",getcsvfield(tmp, 1),getcsvfield(tmp, 2),....... and so on
Please advise.
A more efficient method would be to parse the line once, creating an array of pointers to the tokens. You can then pass the array entries to the execute function like this
execute("INSERT INTO table(a,b,c,d,e,f) VALUES('%s','%s','%s');",token[0],token[1],...
Here's an example that reads lines from a file, breaks the line into tokens, and then prints the tokens.
#include <stdio.h>
#include <string.h>
int getTokens( char *line, char *token[], int maxt )
{
int i;
char *ptr = strtok(line, ";\n");
for ( i = 0; i < maxt; i++ )
{
if ( ptr == NULL )
return i;
token[i] = ptr;
ptr = strtok( NULL, ";\n" );
}
return i;
}
int main( void )
{
const int maxt = 6;
char line[1024];
char *token[maxt];
FILE *fp;
if ( (fp = fopen( "input.csv", "r" )) == NULL )
return 1;
while ( fgets(line, sizeof line, fp) != NULL )
{
int count = getTokens( line, token, maxt );
for ( int i = 0; i < count; i++ )
printf( "%d: '%s'\n", i, token[i] );
printf( "\n" );
}
fclose( fp );
}
I have a text file with:
recipName=Fork friend=Cup sonName=Spork feature=hair sendName=Spoon"
What I want to do is copy all the words before an = sign to one character array, and copy the stuff to the right of the = to another character array or string.
This is my code so far:
int main (int argc, char * argv[])
{
char data[100];
char line[5][100];
char key[5][100];
char value[5][100];
FILE * fdata = fopen(argv[1], "r"); //read data.txt file
FILE * ftemp = fopen(argv[2], "r"); //read and write to template.txt file
if (fdata == NULL)
{
printf("could not read file.\n");
}
int i = 0;
while (fgets(data, 100, fdata) != NULL)
{
printf("data: %s", data);
//this is where i get stuck, idk how to utilize this loop to copy the variable and variable names from the data.txt file i was given...thanks for the help
++i;
}
fclose(fdata);
fclose(ftemp);
return 0;
}
there might be some better functions that will do more of what you want in string.h
you will have to work out the logistics and count the number of '=' characters and decide how to handle that.
#include <string.h>
char *ptr1, *ptr2;
char tempstring[100];
char before[100];
char after[100];
/* you already have data[] filled... where you get stuck */
ptr1 = strchr( data, '=' ); /* find first occurence of = */
ptr2 = strrchr( data, '=' ); /* find last occurence of = */
if ( *ptr1 == '\0' )
{
/* did not find '=' print error message and stop */
}
if ( *ptr2 == '\0' )
{
/* did not find '=' print error message and stop */
}
/* below is what you are interested in */
strcpy( tempstr, data );
ptr1 = strchr( tempstr, '=' );
*ptr1 = '\0'; /* turn = into null */
strcpy( before, tempstr );
printf("everything before = character is %s\n", tempstr ); /* watch out if = is first character, nothing before it */
strcpy( tempstr, data );
ptr2 = strchr( tempstr, '=' );
ptr2++;
if ( *ptr2 != '\0' ) /* = might have been last character */
{
strcpy( after, tempstr );
printf("everything after = character is %s\n", tempstr );
}
so for the first strchr call,
before[] will have "recipName"
and after[] will have "Fork friend=Cup sonName=Spork feature=hair sendName=Spoon"
you can do a
sscanf( after, "%s", after2 );
to get just "Fork" into after2[] array assuming there will always be a space character separating things.
for chqrlie
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
# define MAX 5
int Count_Token ( char str[], char token )
{
char *p;
int cnt = 0;
/* str must be null terminated with '\0' otherwise infinite loop will happen */
p = str;
while ( *p != '\0' )
{
if ( *p == token )
cnt++;
p++;
}
return cnt;
}
void Get_KeyValue_at_Position( char str[], char token, int position, char k[], char v[] )
{
char *ptr;
char temp_str[100];
int i;
ptr = str;
/* assumes str[] passed in does not have leading space before first key */
/* this for loop puts ptr on start of key at position */
for ( i = 0; i < position; i++ }
{
/* move ptr to next space */
while (( *ptr != ' ' ) && ( *ptr != '\0' ))
ptr++;
/* account for more than one space separating key/value pairs and put ptr on beginning of next key */
while ( *ptr == ' ' )
ptr++;
}
/* get key */
strcpy( temp_str, ptr )
ptr_token = strchr( temp_str, token );
*ptr_token = '\0';
strcpy( k, tempstr );
/* get value */
strcpy( temp_str, ptr );
ptr_token = strchr( temp_str, token );
ptr_token++;
strcpy( v, ptr_token );
}
int main ( int argc, char * argv[] )
{
char data[100];
char key[MAX][100]; /* has string before token */
char value[MAX][100]; /* has string afte token */
FILE *fdata;
fdata = fopen(argv[1], "r"); //read data.txt file
if ( fdata == NULL )
{
printf("could not read file %s\n", argv[1] );
exit( 0 );
}
fgets( data, 100, fdata );
while ( ! feof( fdata ) )
{
printf("data: %s", data);
//this is where i get stuck, idk how to utilize this loop to copy the variable and variable names from the data.txt file i was given...thanks for the help
/* count how many token characters there are in data[] string */
num_token = Count_Token( data, '=' );
if ( num_token > MAX )
{
printf(" num token is %d, MAX is %d, stopping program.\n", num_token, MAX );
fclose( fdata );
exit( 0 );
}
for ( i = 0; i < num_token; i++ )
{
/* make sure i index does not exceend declaration size of key and value */
Get_KeyValue_at_Position( data, token, i, key[i], value[i] );
}
fgets( data, 100, fdata );
}
fclose(fdata);
return 0;
}