Comparing certain contents of a string in C - c

So, I have an issue. I'm trying to only get the inside of a string as given by this example:
User input: insert("someWord")
And I want to first make sure that the user spelt insert(" correctly, then I want to copy the string contained inside the " ". As of now, I have a function with a parameter that is the full user input, and inside that function, I have the following:
method header(char *string){
char insert[]="insert(";
if((strncmp(string,insert,6)==0)
{
//the first part was right up to the "
//how do I now get the string contained between " "?
}
else
{ //invalid input
}
}
I'm not even 100% positive the strncmp method is comparing the first 6 letters of the two strings correctly.

sscanf(3) to the rescue:
char insert[31];
int matched = sscanf(string, "insert(\"%[^\"]30s\")", insert);
if (matched) printf("Got %s\n", insert);
This matches a string no larger than 30 characters that doesn't contain a " and is surrounded by insert(" and ").

strncmp will compare the exact number of characters or terminate when it see the first null.
So,
strncmp("inser","insert(",6) // false -- the first string too short
strncmp("insert","insert(",6) // true, the first 6 char match
strncmp("insert(","insert(",6) // true, first 6 char match
strncmp("insertxyz","insert(",6) // true, the first 6 chars match
strncmp("insert","inse",6) // false -- the second string too short
strncmp("append","insert",6) // false -- they just don't match
Note that "insert(" is actually 7 characters long (8 if you include the null byte), so comparing with strncmp(,,6) will not take the training '(' into account -- not sure if that is your problem.
In your case there is no real reason to use strncmp -- just use strcmp instead (or the sscanf solution suggested by a3f)

strchr, strncpy and simple pointer arithmetic can also do the trick, e.g.
method header(char *string){
char insert[]="insert(";
if (strncmp (string, insert, 6) == 0) {
char text[MAXC] = "", *p = string + 7, *ep = NULL;
if ((ep = strchr (p, ')')) && ep - p < MAXC)
strncpy (text, p, ep - p);
printf ("header text: '%s'\n", text);
}
else { //invalid input
}
}
A short example that prints the wanted text between the parenthesis (text cannot contain an embedded close parenthesis).
#include <stdio.h>
#include <string.h>
#define MAXC 128
void header (char *string);
int main (void) {
char string[] = "insert(headerinfo)";
header (string);
return 0;
}
void header (char *string)
{
char insert[] = "insert(";
if (strncmp (string, insert, 6) == 0) {
char text[MAXC] = "", *p = string + 7, *ep = NULL;
if ((ep = strchr (p, ')')) && ep - p < MAXC)
strncpy (text, p, ep - p);
printf ("header text: '%s'\n", text);
}
else { //invalid input
}
}
note: the nul-terminating byte is provided by virtue of initialization. If text is reused with strncpy within the same scope, you should affirmatively nul-terminate text for each subsequent use.
Example Use/Output
$ ./bin/headertxt
header text: 'headerinfo'

Related

Code does not appear to print concatenated strings correctly

I have some code here where, given a .txt file whose contents is
find replace pre
pre
cpre
,I want to find every instance of "pre", and append "k" to it. ie the file should become "find replace kpre".
So I first set out to create a string that is the concatenation of k and pre
(assume k and pre are argv[1] and argv[3], respectively)
char appended[1024];
strcpy(appended, argv[1]);
strcat(appended, argv[3]);
printf("appended string is %s", appended); //prints kpre, which is good
char *replaced = replace(buf, argv[3], appended);
//*string is a line in the file
char* replace(char *string, char *find, char *replace) {
char *position;
char temp[1024];
int find_length = strlen(find);
int index = 0;
while ((position = strstr(string, find)) != NULL) {
strcpy(temp, string);
index = position - string;
string[index] = '\0';
strcat(string, replace); //add new word to the string
strcat(string, temp + index + find_length); //add the unsearched
//remainder of the string
}
return string;
}
.................
fputs(replaced, temp);
Checking on the console, appended = "kpre", which is correct, but when the code is run the file looks like
find replace kkkkkkkkkkkkkkkk.....kkkkkkk
kkkkkkkkk......kkkkk
ckkkkk....kkkkk
the k's go on for a while, I cannot see pre when scrolling all the way to the right. I'm having difficulty figuring out why the code doesn't replace
the instance of 'pre' with 'kpre', even when the appended variable appears to be correct. I have a feeling it has to do with the fact that I set a 1024 character for temp, but even then I'm not sure why k was copied so many times.
Here
while ((position = strstr(string, find)) != NULL) {
you are passing string to strstr() function. The strstr() will return the pointer to the first occurrence of find in string. When you replace pre with kpre and calling again strstr(), it is retuning the pointer to the first occurrence of pre in string which is a sub string of replace string. After some iterations of while loop, it will start accessing the string beyond its size which will lead to undefined behavior.
Instead of passing string to strstr(), you should pass pointer to string and after every replace operation, the make the pointer point to after the replaced part of string. Other way is you can traverse the string character by character using pointer instead of using strstr(), like this:
#define BUFSZ 1024
char* replace(char *string, const char *find, const char *replace) {
if ((string == NULL) || (find == NULL) || (replace == NULL)) {
printf ("Invalid argument..\n");
return NULL;
}
char temp[BUFSZ];
char *ptr = string;
size_t find_len = strlen(find);
size_t repl_len = strlen(replace);
while (ptr[0]) {
if (strncmp (ptr, find, find_len)) {
ptr++;
continue;
}
strcpy (temp, ptr + find_len); // No need to copy whole string to temp
snprintf (ptr, BUFSZ - (ptr - string), "%s%s", replace, temp);
ptr = ptr + repl_len;
}
return string;
}
Note that above code is based on the example you have posted in your question and just to give you an idea about how you can achieve your goal without using strstr(). When writing code, take care of the other possibilities as well like, replace is a huge string.

Matching an exact word using in c

Can I use the strstr function to match exact word? For example, let's say I have the word hello, and an input string line:
if
char* line = "hellodarkness my old friend";
and I use
result = strstr(line, "hello");
result will match (be not NULL), however I want to match only the exact word "hello" (so that "hellodarkness" would not match) and result will be NULL.
Is it possible to do this using strstr or do I have to use fscan and scan the line word by word and check for matches?
Here is a generic function for your purpose. It returns a pointer to the first match or NULL if none can be found:
#include <ctype.h>
#include <string.h>
char *word_find(const char *str, const char *word) {
const char *p = NULL;
size_t len = strlen(word);
if (len > 0) {
for (p = str; (p = strstr(p, word)) != NULL; p++) {
if (p == str || !isalnum((unsigned char)p[-1])) {
if (!isalnum((unsigned char)p[len]))
break; /* we have a match! */
p += len; /* next match is at least len+1 bytes away */
}
}
}
return p;
}
I would:
check if string is in sentence
if found at start (same pointer as line), add the length of the word and check if alphanumerical char found. If not (or null-terminated), then match
if found anywhere else, add the extra "no alphanum before" test
code:
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
int main()
{
const char* line = "hellodarkness my old friend";
const char *word_to_find = "hello";
char* p = strstr(line,word_to_find);
if ((p==line) || (p!=NULL && !isalnum((unsigned char)p[-1])))
{
p += strlen(word_to_find);
if (!isalnum((unsigned char)*p))
{
printf("Match\n");
}
}
return 0;
}
here it doesn't print anything, but insert a punctuation/space before/after or terminate the string after "hello" and you'll get a match. Also, you won't get a match by inserting alphanum chars before hello.
EDIT: the above code is nice when there's only 1 "hello" but fails to find the second "hello" in "hellohello hello". So we have to insert a loop to look for the word or NULL, advancing p each time, like this:
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
int main()
{
const char* line = " hellohello hello darkness my old friend";
const char *word_to_find = "hello";
const char* p = line;
for(;;)
{
p = strstr(p,word_to_find);
if (p == NULL) break;
if ((p==line) || !isalnum((unsigned char)p[-1]))
{
p += strlen(word_to_find);
if (!isalnum((unsigned char)*p))
{
printf("Match\n");
break; // found, quit
}
}
// substring was found, but no word match, move by 1 char and retry
p+=1;
}
return 0;
}
Since strstr() returns the pointer to the starting location of the substring that you want to identify, then you can use strlen(result) the check if it is a substring of longer string or the isolated string that you are looking for. if strlen(result) == strlen("hello"), then it ends correctly. If it ends with a space or punctuation (or some other delimiter), then it is also isolated at the end. You would also need to check if the start of the substring is at the beginning of the "long string" or preceded by a blank, punctuation, or other delimiter.

Get an Array of Strings Between Two Strings in C

I'm looking for a very simple way to return an array of strings that are contained between trailing and leading strings. Here's an example:
char *text = ;;;Text I want]]] Text I don't care about ;;;More Text I want]]] More text I don't care about
Calling stringBetweenString(";;;","]]]",text) should return an array (const char *myArray[2]) with the following values: "Text I want","More Text I want".
Unfortunately, I do not have access to RegEx for this application, nor external libraries. Any help would be greatly appreciated, thanks!
There is no need for a regex, as others have noted strstr will search within a string for the occurrence of a substring, returning a pointer to the beginning of the substring on success, NULL otherwise. You can use that with simple pointer arithmetic to parse the wanted text from between the substrings, e.g.:
#include <stdio.h>
#include <string.h>
#define MAXC 128
int main (void) {
char *text = ";;;Text I want]]] Text I don't care about ;;;More "
"Text I want]]] More text I don't care about";
char buf[MAXC] = "", *p = text, *ep;
while ((p = strstr (p, ";;;"))) {
if ((ep = strstr (p, "]]]"))) {
strncpy (buf, p + 3, ep - p - 3);
buf[ep - p - 3] = 0;
printf ("buf: '%s'\n", buf);
}
else
break;
p = ep;
}
return 0;
}
Example Use/Output
$ ./bin/splitbetween
buf: 'Text I want'
buf: 'More Text I want'

Rotate words around vowels in C

I am trying to write a program that reads the stdin stream looking for words (consecutive alphabetic characters) and for each word rotates it left to the first vowel (e.g. "friend" rotates to "iendfr") and writes this sequence out in place of the original word. All other characters are written to stdout unchanged.
So far, I have managed to reverse the letters, but have been unable to do much more. Any suggestions?
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define MAX_STK_SIZE 256
char stk[MAX_STK_SIZE];
int tos = 0; // next available place to put char
void push(int c) {
if (tos >= MAX_STK_SIZE) return;
stk[tos++] = c;
}
void putStk() {
while (tos >= 0) {
putchar(stk[--tos]);
}
}
int main (int charc, char * argv[]) {
int c;
do {
c = getchar();
if (isalpha(c) && (c == 'a' || c == 'A' || c == 'e' || c == 'E' || c == 'i' || c == 'o' || c == 'O' || c == 'u' || c == 'U')) {
push(c);
} else if (isalpha(c)) {
push(c);
} else {
putStk();
putchar(c);
}
} while (c != EOF);
}
-Soul
I am not going to write the whole program for you, but this example shows how to rotate a word from the first vowel (if any). The function strcspn returns the index of the first character matching any in the set passed, or the length of the string if no matches are found.
#include <stdio.h>
#include <string.h>
void vowelword(const char *word)
{
size_t len = strlen(word);
size_t index = strcspn(word, "aeiou");
size_t i;
for(i = 0; i < len; i++) {
printf("%c", word[(index + i) % len]);
}
printf("\n");
}
int main(void)
{
vowelword("friend");
vowelword("vwxyz");
vowelword("aeiou");
return 0;
}
Program output:
iendfr
vwxyz
aeiou
There are a number of ways your can approach the problem. You can use a stack, but that just adds handling the additional stack operations. You can use a mathematical reindexing, or you can use a copy and fill solution where you copy from the first vowel to a new string and then simply add the initial characters to the end of the string.
While you can read/write a character at a time, you are probably better served by creating the rotated string in a buffer to allow use of the string within your code. Regardless which method you use, you need to validate all string operations to prevent reading/writing beyond the end of your input and/or rotated strings. An example of a copy/fill approach to rotating to the first vowel in your input could be something like the following:
/* rotate 's' from first vowel with results to 'rs'.
* if 's' contains a vowel, 'rs' contains the rotated string,
* otherwise, 'rs' contais 's'. a pointer to 'rs' is returned
* on success, NULL otherwise and 'rs' is an empty-string.
*/
char *rot2vowel (char *rs, const char *s, size_t max)
{
if (!rs || !s || !max) /* validate params */
return NULL;
char *p = strpbrk (s, "aeiou");
size_t i, idx, len = strlen (s);
if (len > max - 1) { /* validate length */
fprintf (stderr, "error: insuffieient storage (len > max - 1).\n");
return NULL;
}
if (!p) { /* if no vowel, copy s to rs, return rs */
strcpy (rs, s);
return rs;
}
idx = p - s; /* set index offset */
strcpy (rs, p); /* copy from 1st vowel */
for (i = 0; i < idx; i++) /* rotate beginning to end */
rs[i+len-idx] = s[i];
rs[len] = 0; /* nul-terminate */
return rs;
}
Above, strpbrk is used to return a pointer to the first occurrence of a vowel in string 's'. The function takes as parameters a pointer to a adequately sized string to hold the rotated string 'rs', the input string 's' and the allocated size of 'rs' in 'max'. The parameters are validated and s is checked for a vowel with strpbrk which returns a pointer to the first vowel in s (if it exists), NULL otherwise. The length is checked against max to insure adequate storage.
If no vowels are present, s is copied to rs and a pointer to rs returned, otherwise the pointer difference is used to set the offset index to the first vowel, the segment of the string from the first vowel-to-end is copied to rs and then the preceding characters are copied to the end of rs with the loop. rs is nul-terminated and a pointer is returned.
While I rarely recommend the use of scanf for input, (a fgets followed by sscanf or strtok is preferable), for purposes of a short example, it can be used to read individual strings from stdin. Note: responding to upper/lower case vowels is left to you. A short example setting the max word size to 32-chars (31-chars + the nul-terminating char) will work for all known words in the unabridged dictionary (longest word is 28-chars):
#include <stdio.h>
#include <string.h>
enum { BUFSZ = 32 };
char *rot2vowel (char *rs, const char *s, size_t max);
int main (void)
{
char str[BUFSZ] = {0};
char rstr[BUFSZ] = {0};
while (scanf ("%s", str) == 1)
printf (" %-8s => %s\n", str, rot2vowel (rstr, str, sizeof rstr));
return 0;
}
Example Use/Output
(shamelessly borrowing the example strings from WeatherVane :)
$ echo "friend vwxyz aeiou" | ./bin/str_rot2vowel
friend => iendfr
vwxyz => vwxyz
aeiou => aeiou
Look it over and let me know if you have any questions. Note: you can call the rot2vowel function prior to the printf statement and print the results with rstr, but since the function returns a pointer to the string, it can be used directly in the printf statement. How you use it is up to you.

c, delete words which contain digits from a string

I need to delete all words that contain digits from the string.
E.g. if input is abdgh 67fgh 32ghj hj dfg43 11 fg, output should be abdgh hj fg.
I thought of using while( text[i] != ' '), but I don't know how to continue it for the rest of the string (after the first whitespace).
I don't have any other idea, and couldn't find anything by googling. Please, help me!
Here, i gave it a try. Works just fine for me. I tried to explain the logic throughout the code via comments. Hope it helps.
#include <stdio.h>
#include <string.h>
int containsNum(char * str);
int main()
{
char str[] = "abdgh 67fgh 32ghj hj dfg43 11 fg"; // input string
char newstr[100] = ""; //new string to create with filtered data
char * pch; //temp string to use in strtok
printf("given string : %s\n",str );
pch = strtok (str," ");
while (pch != NULL)
{
if(!containsNum(pch))// creation of new string with strcat
{ // if the current word not contains any number
strcat(newstr,pch);
strcat(newstr," "); //adding a space between words for readability
}
pch = strtok (NULL, " ");
}
printf("modified string : %s\n", newstr );
return 0;
}
//function containsNum
//gets a string and checks if it has any numbers in it
//returns 1 if so , 0 otherwise
int containsNum(char * str)
{
int i,
size =strlen(str),
flag=0;
for(i=0; i<size ; ++i)
{
if((int)str[i] >=48 && (int)str[i] <=57 ){
flag =1;
break;
}
}
return flag;
}
Regards
Algorithm:
1-You will have to break your input string into smaller components which are also called as tokens. For example: for the string abdgh 67fgh 32ghj hj dfg43 11 fg the tokens could be abdgh, 67fgh, 32ghj, hj, dfg43, 11 and fg.
2- These smaller strings or tokens can be formed using the strtok function which is defined as
char * strtok ( char * str, const char * delimiters );. Thestr in the first argument is the input sting which in the code presented below is string1. The second argument called the delimiters is what actually defines when to divide the input string into smaller pieces(tokens).
For instance, a whitespace as a delimiter will divide the input string whenever a whitespace is encountered, which is how the string is being divided in the code.
3-Since, your program needs to delete those words in the input string which contain digits we can use the isdigit() function to check exactly that.
WORKING CODE:
#include <cstring>
#include <ctype.h>
#include<stdio.h>
int main ()
{
char output[100]="";
int counter;
int check=0; /* An integer variable which takes the value of "1" whenever a digit
is encountered in one of the smaller strings or tokens.
So, whenever check is 1 for any of the tokens that token is to be ignored, that is,
not shown in the output string.*/
char string1[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
char delimiters[] = " ";//A whitespace character functions as a delimiter in the program
char * token;//Tokens are the sub-strings or the smaller strings which are part of the input string.
token=strtok(string1,delimiters);/*The first strktok call forms the first token/substring which for the input
given would be abdgh*/
while(token!=NULL)/*For the last substring(token) the strtok function call will return a NULL pointer, which
also indicates the last of the tokens(substrings) that can be formed for a given input string.
The while loop finishes when the NULL pointer is encountered.*/
{
for(counter=0;counter<=strlen(token)-1;counter++)/*This for loop iterates through each token element.
Example: In case of abdgh, it will first check for 'a',
then 'b', then 'd' and so on..*/
{
if(isdigit((int)token[counter])>0)/*This is to check if a digit has been encountered inside a token(substring).
If a digit is encountered we make check equal to 1 and break our loop, as
then that token is to be ignored and there is no real need to iterate
through the rest of the elements of the token*/
{
check=1;
break;
}
}
if(check==1) /* Outside the for loop, if check is equal to one that means we have to ignore that token and
it is not to be made a part of the output string. So we just concatenate(join) an
empty string ( represented by " " )with the output string*/
{
strcat(output,"");
check=0;
}
else /*If a token does not contain any digit we simply make it a part of the output string
by concatenating(joining) it with the output string. We also add a space for clarity.*/
{
strcat(output,token);
strcat(output," ");
}
token = strtok( NULL, delimiters ); /*This line of code forms a new token(substring) every time it is executed
inside the while loop*/
}
printf( "Output string is:: %s\n", output ); //Prints the final result
return 0;
}
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
char *filter(char *str){
char *p, *r;
p = r = str;
while(*r){
char *prefetch = r;
bool contain_digit = false;
while(!isspace(*prefetch) && *prefetch){
if(contain_digit)
++prefetch;
else if(isdigit(*prefetch++))
contain_digit = true;
}
if(contain_digit){
r = prefetch;
}else {
while(r < prefetch){
*p++ = *r++;
}
}
if(!*r)
break;
if(p[-1] == *r)
++r;
else
*p++ =*r++;
}
*p = '\0';
return str;
}
int main(void) {
char text[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
printf("%s\n", filter(text));//abdgh hj fg
return 0;
}

Resources