I am trying to extract the name of a store from strings that are stored as char arrays using the language C. Each one contains the price of an item and the store it is located at. I have many strings that follow this format, but I have provided I few examples below:
199 at Amazon
139 at L.L.Bean
379.99 at Best Buy
345 at Nordstrom
How could I extract the name of the store from these strings?
Thank you in advance.
const char *sought = "at ";
char *pos = strstr(str, sought);
if(pos != NULL)
{
pos += strlen(sought);
// pos now points to the part of the string after "at";
}
else
{
// sought was not find in str
}
If you want to extract a portion after pos, but not the entire remaining string, you can use memcpy:
const char *sought = "o ";
char *str = "You have the right to remain silent";
char *pos = strstr(str, sought);
if(pos != NULL)
{
char word[7];
pos += strlen(sought);
memcpy(word, pos, 6);
word[6] = '\0';
// word now contains "remain\0"
}
As it was already pointed in comments you can use standard function strstr.
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
char * extract_name( const char *record, const char *prefix )
{
size_t n = 0;
const char *pos = strstr( record, prefix );
if ( pos )
{
pos += strlen( prefix );
while ( isblank( ( unsigned char )*pos ) ) ++pos;
n = strlen( pos );
}
char *name = malloc( n + 1 );
if ( name )
{
if ( pos )
{
strcpy( name, pos );
}
else
{
*name = '\0';
}
}
return name;
}
int main(void)
{
const char *prefix = "at ";
char *name = extract_name( "199 at Amazon", prefix );
puts( name );
free( name );
name = extract_name( "139 at L.L.Bean", prefix );
puts( name );
free( name );
name = extract_name( "379.99 at Best Buy", prefix );
puts( name );
free( name );
name = extract_name( "345 at Nordstrom", prefix );
puts( name );
free( name );
return 0;
}
The program output is
Amazon
L.L.Bean
Best Buy
Nordstrom
The function extract_name creates dynamically a character array where it stores the extracted name. If the memory allocation is failed the function returns a null pointer. If the prefix before the name ( in this case it is the string "at ") is not found the function returns an empty string.
Related
I want to know how to count how many words are in a string.
I use strstr to compare and it works but only works for one time
like this
char buff = "This is a real-life, or this is just fantasy";
char op = "is";
if (strstr(buff,op)){
count++;
}
printf("%d",count);
and the output is 1 but there are two "is" in the sentence, please tell me.
For starters you have to write the declarations at least like
char buff[] = "This is a real-life, or this is just fantasy";
const char *op = "is";
Also if you need to count words you have to check whether words are separated by white spaces.
You can do the task the following way
#include <string.h>
#include <stdio.h>
#include <ctype.h>
//...
size_t n = strlen( op );
for ( const char *p = buff; ( p = strstr( p, op ) ) != NULL; p += n )
{
if ( p == buff || isblank( ( unsigned char )p[-1] ) )
{
if ( p[n] == '\0' || isblank( ( unsigned char )p[n] ) )
{
count++;
}
}
}
printf("%d",count);
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char buff[] = "This is a real-life, or this is just fantasy";
const char *op = "is";
size_t n = strlen( op );
size_t count = 0;
for ( const char *p = buff; ( p = strstr( p, op ) ) != NULL; p += n )
{
if ( p == buff || isblank( ( unsigned char )p[-1] ) )
{
if ( p[n] == '\0' || isblank( ( unsigned char )p[n] ) )
{
count++;
}
}
}
printf( "The word \"%s\" is encountered %zu time(s).\n", op, count );
return 0;
}
The program output is
The word "is" is encountered 2 time(s).
Parse the string, in a loop.
As OP has "but there are two "is" in the sentence", it is not enough just to look for "is" as that occurs 4x, twice in "This". Code needs to parse the string for the idea of a "word".
Case sensitively is also a concern.
char buff = "This is a real-life, or this is just fantasy";
char op = "is";
char *p = buff;
char *candidate;
while ((candidate = strstr(p, op)) {
// Add code to test if candidate is a stand-alone word
// Test if candidate is beginning of buff or prior character is a white-space.
// Test if candidate is end of buff or next character is a white-space/punctuation.
p += strlen(op); // advance
}
For me, I would not use strstr(), but look for "words" with isalpha().
// Concept code
size_t n = strlen(op);
while (*p) {
if (isalpha(*p)) { // Start of word
// some limited case insensitive compare
if (strnicmp(p, op, n) == 0 && !isalpha(p[n]) {
count++;
}
while (isalpha(*p)) p++; // Find end of word
} else {
p++;
}
}
For example:
str = "I have a meeting"
word = "meet"
should give 0 since there is no such word
I tried strstr(str, word) but it checks for substring, so it gives 1 for this example
I assume that words are sequences of characters separated by blank characters.
You can use the function strstr but you need also to check that blanks precede and follow the found substring or that the returned pointer points to the beginning of the sentence or the found substring forms the tail of the sentence.
Here is a demonstration program that shows how such a function can be defined.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char * is_word_present( const char *sentence, const char *word )
{
const char *p = NULL;
size_t n = strlen( word );
if ( n != 0 )
{
p = sentence;
while ( ( p = strstr( p, word ) ) != NULL )
{
if ( ( p == sentence || isblank( ( unsigned char )p[-1] ) ) &&
( p[n] == '\0' || isblank( ( unsigned char )p[n] ) ) )
{
break;
}
else
{
p += n;
}
}
}
return ( char * )p;
}
int main( void )
{
char *p = is_word_present( "I have a meeting", "meet" );
if ( p )
{
puts( "The word is present in the sentence" );
}
else
{
puts( "The word is not present in the sentence" );
}
p = is_word_present( "I meet you every day", "meet" );
if ( p )
{
puts( "The word is present in the sentence" );
}
else
{
puts( "The word is not present in the sentence" );
}
return 0;
}
The program output is
The word is not present in the sentence
The word is present in the sentence
I was taking a look at the 2 C-string functions, strtok_r() and strsep(), and noticed both
functions modify the location of the original string passed in.
Are there any other C-string functions that don't modify the original string passed in?
In my application, the original string is dynamically allocated, so I wish to free the original
string after the parsing is done.
An example with strtok_r()
int main(){
char * str = strdup("Tutorial and example");
char* token;
char* rest = str;
printf("%s\n", rest);
while ((token = strtok_r(rest, " ", &rest)))
printf("%s\n", token);
printf("\n%s\n",str);
return(0);
}
Output
Tutorial and example
Tutorial
and
example
Tutorial
In the very last line, I wish for str to point to the unmodified cstring "Tutorial and example".
A similar output would have occured with strsep() as well.
int main(){
char * str = strdup("Tutorial and example");
char* token;
char* rest = str;
printf("%s\n", rest);
while ((token = strsep(&rest, " ")))
printf("%s\n", token);
if (rest != NULL)
printf("%s\n", rest);
printf("%s\n", str);
return(0);
}
Thank you.
I think you are misunderstanding strtok_r. It does not change the location of the original string, moreover, it can not - the function can not change the value of the pointer passed into it and make this change visible to the calling code.
What it can and will do is modifying the contents of the string itself, by replacing tokens with nul-terminators. So to answer your original question:
In my application, the original string is dynamically allocated, so I
wish to free the original string after the parsing is done.
You do not have to do anything special. You can and should free original string after you are done with it.
You are seeing a single word Tutorial printed simply because the next character was replaced with nul-terminator and printf stop there. If you are to inspect the string character by character, you will see that it otherwise have remained intact.
Though the mentioned string functions change the original string nevertheless the pointer str points to the dynamically allocated memory and you may use it to free the allocated memory.
if you do not want to change the original string you can use standard C string functions strspn and strcspn.
For example
#include <stdio.h>
#include <string.h>
int main(void)
{
const char *s = "Tutorial and example";
const char *separator = " \t";
puts( s );
for ( const char *p = s; *p; )
{
p += strspn( p, separator );
const char *prev = p;
p += strcspn( p, separator );
int width = p - prev;
if ( width ) printf( "%.*s\n", width, prev );
}
return 0;
}
The program output is
Tutorial and example
Tutorial
and
example
Using this approach you can dynamically allocate memory for each extracted substring.
For example
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
const char *s = "Tutorial and example";
const char *separator = " \t";
puts( s );
size_t n = 0;
char **a = NULL;
int success = 1;
for ( const char *p = s; success && *p; )
{
p += strspn( p, separator );
const char *prev = p;
p += strcspn( p, separator );
if ( p - prev != 0 )
{
char *t = malloc( p - prev + 1 );
if ( ( success = t != NULL ) )
{
t[p - prev] = '\0';
memcpy( t, prev, p - prev );
char **tmp = realloc( a, ( n + 1 ) * sizeof( char * ) );
if ( ( success = tmp != NULL ) )
{
a = tmp;
a[n++] = t;
}
else
{
free( t );
}
}
}
}
for ( size_t i = 0; i < n; i++)
{
puts( a[i] );
}
for ( size_t i = 0; i < n; i++)
{
free( a[i] );
}
free( a );
return 0;
}
The program output is the same as shown above.
Tutorial and example
Tutorial
and
example
#include <stdio.h>
#include <string.h>
int main(void){
char sen[100];
char word[30];
char rep[30];
printf("Enter a sentence> ");
gets(sen);
printf("Enter a word to compare> ");
gets(word);
printf("Enter a word to replace with> ");
gets(rep);
int sen_len = strlen(sen);
int word_len = strlen(word);
char temp[30];
char retSen[100];
char rest[70];
int i;
int y=0;
for(i=0; i<sen_len; i++){
//Loop through characters in sentence until you reach a whitespace. ie, extract a word and put it in temp.
if(sen[i] == ' '){
//Compare the word with target word
if(!strcmp(temp, word)){
//In case of match, copy the part upto but not including the matching word and put it in the final string (retSen)
strncpy(retSen, sen, sen_len-i);
}else{
//Clear temp and skip to next iteration
y=0;
temp[0] = '\0';
continue;
}
}
y++;
//Repeatedly populate y with a word from sen
temp[y] = sen[i];
}
int x=0;
for(int j=i; j<sen_len; j++){
//Populate another char array with the rest of the sentence after the matching word.
rest[x] = sen[j];
}
//Join the part upto the matching word with the replacing word.
strcat(retSen, rep);
//Then join the rest of the sentence after the matching word to make the full string with the matching word replaced.
strcat(retSen, rest);
puts(retSen);
return 0;
}
I'm trying to make a program that will take a sentence, a target word to replace and another word to replace the target with. This code isn't working. It just prints the replacing word + 'a' for some reason. How can I fix this code?
In C, you need to build your own string substitution functions. I think that your use case could make good use of the strtok(), strcat() and strncat() functions,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Prototypes:
int searchForWord( const char * haystack, const char * needle );
char * searchAndReplace( const char * haystack, const char * needle, const char * newNeedle );
/**
* main
*/
int main()
{
const char * sentence = "The quick brown fox jumped over the lazy dog." ;
const char * wordToReplace = "fox" ;
const char * replacementWord = "turtle" ;
// ... Search and replace...
char * newSentence = searchAndReplace( sentence, wordToReplace, replacementWord ) ;
// ... Show the result
if ( newSentence ) {
printf( "%s\n", newSentence ) ;
free( newSentence ) ;
} else {
printf( "%s\n", sentence ) ;
}
return 0;
}
/**
* Take a sentence, and replace the first occurrence of a word with another word.
*
* Parameters:
* haystack: the original sentence
* needle: the word to search and replace
* newNeed: the word to use as replacement
*
* Returns:
* A new modified string, or NULL if the word was never found.
*
* Note:
* The result is dynamically allocated so it mut be freed once no longer needed.
*/
char * searchAndReplace( const char * haystack, const char * needle, const char * newNeedle )
{
// ... Is the word in the sentence?
int offset = searchForWord( haystack, needle ) ;
if ( offset < 0 ) {
fprintf( stderr, "searchAndReplace: %s not found in the given setence\n", needle );
return NULL;
}
// ... From the found offset, determine the end offset of the word
int offsetEnd = offset + strlen(needle);
// ... Create a new buffer that will contain the modified sentence
int newSize = strlen( haystack ) - strlen( needle ) + strlen( newNeedle ) + 1 ;
char * result = (char*)malloc( newSize * sizeof(char) ) ;
// ... Initialize the new buffer to a zero-length string
result[ 0 ] = '\0';
// ... Build the new sentence: first part (before the found word)
if ( offset > 0 ) {
strncat( result, haystack, offset) ;
}
// ... Build the new sentence: replaced word
strcat( result, newNeedle ) ;
// ... Build the new sentence: last part
strncat( result, &haystack[ offsetEnd ], strlen(&haystack[ offsetEnd ]) ) ;
return result ;
}
/**
* Find the location of a word in a sentence, assuming words are whitespace-
* delimited.
*
* Returns: offset of the word in the sentence, or -1 if not found
*/
int searchForWord( const char * haystack, const char * needle )
{
int result = -1 ;
const char * delims = " \n\r\t" ; // whitespaces
// ... Get a copy of haystack, as strtok() will alter it
char * copy = strdup(haystack) ;
// ... For each word in the sentence
for ( char *p = strtok( copy, delims ); p != NULL; p = strtok( NULL, delims ) ) {
// ... If the word matches what we're looking for
if ( strcmp( p, needle ) == 0 ) {
// ... Set the offset in the sentence
result = p - ©[ 0 ] ;
// ... We're done searching
break ;
}
}
// .... Avoid memory leaks
free( copy ) ;
// ... Return whatever we found (or not)
return result ;
}
Hello and sorry if this questions is already answered (in the way I want to :-) ) but I think I have a memory problem.
Assuming the following C function (yes, this one is very dirty and not optimized):
char *strreplace(char **str, char *dst, char *replace) {
int replacestart = stringcompare(*str, dst), replaceend = strlen(dst), replacelen = strlen(replace);
char *tmp1 = (char *)malloc(sizeof(char) * (replacestart + 1)), *tmp2 = (char *)malloc(sizeof(char) * ((strlen(*str) - replaceend) + 1));
memset(tmp1, 0, sizeof(char) * (replacestart + 1));
memset(tmp2, 0, sizeof(char) * ((strlen(*str) - replaceend) + 1));
strncpy(tmp1, *str, replacestart);
strncpy(tmp2, *str + replacestart + replaceend, (strlen(*str) - (replaceend + replacestart)));
*str = realloc(*str, strlen(tmp1) + replacelen + strlen(tmp2));
memset(*str, 0, strlen(tmp1) + replacelen + strlen(tmp2));
strncpy(*str, tmp1, strlen(tmp1));
strncpy(*str + strlen(tmp1), replace, replacelen);
strncpy(*str + strlen(tmp1) + replacelen, tmp2, strlen(tmp2));
return *str;
}
As seen, it should replace *dst with *replace whithin **str.
This works basically as expected. Here's the problem:
The output (*str) is not cleard out with zeros after memsetting it and has still the wrong length, even after reallocating.
Means, if the string is longer after replacing, the last chars are cutted of *str.
In turn, if the string is shorter, old chars are at the end of the char string are found.
What did I wrong. Mentioned that I don't want to use sprintf and no C++-STL, just want to do this with pointers in C.
Other words, what would be the right way to replace a string in an c char string with pointers.
Thanks alot.
EDIT after reqeuest for more information
I use this function as following:
...open a textfile via FILE type, determining file lengts (fseek)...
char *filecontent = (char *)malloc(sizeof(char) * filesize);
if(filesize != fread(filecontent, sizeof(char), filesize, fd)) {
free(filecontent);
return -1;
}
streplace(&filecontent, "[#TOBEREPLACED#]", "replaced");
...doing other stuff with filecontent...
EDIT 2, adding stringcompare()
int stringcompare(const char *string, const char *substr) {
int i, j, firstOcc;
i = 0, j = 0;
while(string[i] != '\0') {
while(string[i] != substr[0] && string[i] != '\0') {
i++;
}
if(string[i] == '\0') {
return -1;
}
firstOcc = i;
while(string[i] == substr[j] && string[i] != '\0' && substr[j] != '\0') {
i++;
j++;
}
if(substr[j] == '\0') {
return firstOcc;
}
if(string[i] == '\0') {
return -1;
}
i = firstOcc + 1;
j = 0;
}
}
The logic of the function is not simple as it seems at the first glance.
You should decide what action to execute 1) if the source string is empty and 2) if the destination string is empty.
For example if the destination string is empty then the standard function strstr will return the address of the first character of the source string. However logically if dst is an empty string then the source string should not be changed except the case when it is in turn an empty string. In this case the function should just create a new string equal to the string replace.
Take into account that as the strings dst and replace are not changed within the function they should be declared with the qualifier const.
char * strreplace( char **str, const char *dst, const char *replace );
Also the function should report whether a new memory allocation was successful within the function by returning a null pointer in case when the allocation failed.
Taking all this into account the function can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * strreplace( char **str, const char *dst, const char *replace )
{
char *result = *str;
if ( *str[0] == '\0' )
{
if ( dst[0] == '\0' && replace[0] != '\0' )
{
char *result = malloc( strlen( replace ) + 1 );
if ( result )
{
strcpy( result, replace );
free( *str );
*str = result;
}
}
}
else if ( dst[0] != '\0' )
{
char *pos = strstr( *str, dst );
if ( pos != NULL )
{
size_t dst_n = strlen( dst );
size_t replace_n = strlen( replace );
result = ( char * )malloc( strlen( *str ) - dst_n + replace_n + 1 );
if ( result )
{
size_t n = pos - *str;
strncpy( result, *str, n );
strcpy( result + n, replace );
strcpy( result + n + replace_n, *str + n + dst_n );
}
free( *str );
*str = result;
}
}
return result;
}
int main(void)
{
const char *hello = "Hello everybody here";
char *str = malloc( sizeof( char ) );
str[0] = '\0';
if ( strreplace( &str, "", hello ) )
{
puts( str );
}
if ( strreplace( &str, "everybody", "Eurobertics" ) )
{
puts( str );
}
if ( strreplace( &str, "Hello", "Bye" ) )
{
puts( str );
}
if ( strreplace( &str, " here", "" ) )
{
puts( str );
}
if ( strreplace( &str, "Bye ", "" ) )
{
puts( str );
}
free( str );
return 0;
}
The program output is
Hello everybody here
Hello Eurobertics here
Bye Eurobertics here
Bye Eurobertics
Eurobertics
Your function looks overly complex. Here is a simple, working version:
char *strreplace(char **str, char *dst, char *replace) char *strreplace(char **str, char *dst, char *replace)
{
char *start, *tmp;
int n;
if ((start=strstr(*str,dst))==0) return(0);
n= (start-*str) + strlen(start+strlen(dst)) + strlen(replace) + 1;
tmp=malloc(n);
strncpy(tmp,*str,start-*str);
strcpy(tmp+(start-*str),replace);
strcat(tmp,start+strlen(dst));
free(*str);
*str= tmp;
return(tmp);
}
With test function:
void reptest(void)
{
char *src;
char rep[]= "brave new world";
src=malloc(strlen("Hello world of wonders")+1);
strcpy(src,"Hello world of wonders");
strreplace(&src,"world",rep);
printf("%s\n", src);
free(src);
}
Edit: my previous version forgot to copy the remainder. Fixed.