I need to extract both "rudolf" and "12" from that long string: "hello, i know that rudolph=12 but it so small..." using scanf, how can I do it?
This buffer can contains any formatted strings like ruby=45 or bomb=1, and I dont know it in advance.
I am trying something like that, but it was unsuccessful
#include <stdio.h>
int main()
{
char sentence[] = "hello, i know that rudolph=12 but it so small...";
char name[32];
int value;
sscanf(sentence, "%[a-z]=%d", name, &value);
printf("%s -> %d\n", name, value);
getchar();
return 0;
}
Iterate through the sentence using a temporary pointer and %n to extract each sub-string.
%n will give the number of characters processed by the scan to that point. Add that to the temporary pointer to advance through the sentence.
Try to parse from each sub-string the name and value. The scanset %31[^=] will scan a maximum of 31 characters, leaving room in name for a terminating zero. It will scan all characters that are not an =. Then the format string will scan the = and try to scan an integer.
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char sentence[] = "hello, i know that rudolph=12 but it so small...";
char string[sizeof sentence] = "";
char name[32] = "";
char *temp = sentence;
int value = 0;
int count = 0;
int parsed = 0;
while (1 == sscanf(temp, "%s%n", string, &count)) {
temp += count;
if (2 == sscanf(string, "%31[^=]=%d", name, &value)) {
parsed = 1;
break;
}
}
if (parsed) {
printf("%s %d\n", name, value);
}
return 0;
}
You can write your own string serach engine. Which could be quite simple, let's for example:
advance until you find one of [a-z]
remember position
advance until the end of [a-z]
check if it's = now
if it is, there was our variable name
advance until end of value
return it
if there's no =, omit everything that is not a [a-z] ie. can't be variable name
A sample program:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
struct find_assignment_s {
const char *line;
const char *var;
size_t varlen;
const char *val;
size_t vallen;
};
struct find_assignment_s find_assignment_init(const char *line) {
return (struct find_assignment_s){.line = line};
}
int find_assignment(struct find_assignment_s *t) {
while (*t->line) {
const char *p = t->line;
while (*p && isalpha((unsigned char)*p)) p++;
// There is at least one alphabetic character and there is a space right after.
if (t->line != p && *p == '=') {
// Found a "variable="!
t->var = t->line;
t->varlen = p - t->line;
// value is up until a space is found
t->val = p + 1;
while (*p && !isspace((unsigned char)*p)) p++;
t->vallen = p - t->val;
// Advance the pointer behind value.
t->line = *p ? p + 1 : p;
return 1;
}
// Ignore spaces
while (*p && !isalpha((unsigned char)*p)) p++;
// Advance over whole word.
t->line = p;
}
return 0;
}
int main() {
const char line[] = "hello, i know that rudolph=12 but it so small... a=b c=d fdnajn=123";
for (struct find_assignment_s fs = find_assignment_init(line);
find_assignment(&fs) == 1; ) {
printf("%.*s = %.*s\n", (int)fs.varlen, fs.var, (int)fs.vallen, fs.val);
}
}
outputs:
rudolph = 12
a = b
c = d
fdnajn = 123
Related
I have a problem I am trying to solve. I have an array of string and integers and I want to convert only the integers(163) to actual integers in C.
I have managed to locate my desired numbers (163) array location but i am unsure how to convert them to numbers. I have tried to use strtol, atoi and strtoumax but I havent been succesful.
I have added my code below.
char busy[30] = {"this is; it was; 163; 234;;"};
int tag = 0;
int location = 0;
for (int i = sizeof(busy); i > 0; i--) {
printf("%c\n", busy[i]);
if (busy[i] == ';') {
tag = tag+1;
printf("tag is %i \n", tag);
}
if (tag == 4) {
printf("for loop is %i\n", i);
location = i;
break;
}
}
location = location+1;
int loca_saved = 0;
int loca_finish = 0;
int tag1 = 0;
while (busy[location] != ';') {
if (busy[location] == ' ' && busy[location - 1] == ';') {
//printf("not printing whitespace between semicolon and characters\n");
location++;
}
else {
if (tag1 == 0) {
tag1 = tag1+1;
loca_saved = location; //this is to tell me the array location for the first char
}
if (busy[location + 1] == ';') {
loca_finish = location; //this is to tell me the array location for the last char
}
putchar(busy[location]); //this is to print my desired characters(163)
location++;
}
}
strspn and strcspn can be used to parse a string.
Instead of sscanf, strtol could be used to get the number.
#include <stdio.h>
#include <string.h>
int main ( void) {
char busy[] = "this is; it was; 163; 234;";
char *dlm = "0123456789";
char *parse = busy;
int number = 0;
while ( *parse) {
parse += strcspn ( parse, dlm);//count to next delimiter
if ( 1 == sscanf ( parse, "%d", &number)) {
printf ( "%d\n", number);
}
parse += strspn ( parse, dlm);//skip delimeters
}
return 0;
}
Parsing could also work off the semicolon.
Some fields will not have an integer.
#include <stdio.h>
#include <string.h>
int main ( void) {
char busy[] = "this is; it was; 163; 234;";
char *dlm = ";";
char *parse = busy;
int number = 0;
while ( *parse) {
if ( 1 == sscanf ( parse, "%d", &number)) {
printf ( "%d\n", number);
}
else {
printf ( "could not parse integer\n");
}
parse += strcspn ( parse, dlm);//count to next delimiter
parse += strspn ( parse, dlm);//skip delimeters
//the above line will skip all consecutive delimiters
//to process each delimiter use the line below
//++parse;//skip one delimiter
}
return 0;
}
Since you have a modifiable string you can use strtok to separate it into substrings based on the ; delimiter. This code does that in in case a substring is a number, it gets printed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
char str[30] = {"this is; it was; 163; 234;;"};
for(char* p=strtok(str, ";"); p!=NULL; p=strtok(NULL,str))
{
char* endptr;
int i = strtol(p,&endptr,10);
if(endptr != p)
{
printf("%d\n", i);
}
}
}
Output:
163
234
strtol sets the "endptr" parameter to point at the beginning of the string in case it fails, so we can use that to determine if a substring was a number or not.
It all depends on the exact grammar that you would like to parse. Note, for example, that negative integers start with a - character, and that there has to be a maximum integer value. Since you are working quite "low level", you may want to perform the conversion to an integer while you are reading the string, e.g.:
#include <ctype.h>
#include <stdio.h>
int main(void)
{
char busy[30] = {"this is; it was; 163; 234;;"};
for (char *p = busy; *p; ++p) // Loop over the string
if (isdigit(*p)) // Found first digit of an unsigned integer
{
unsigned n = (unsigned) (*p - '0'); // Store the value of the first digit in 'n'
// While reading the number, shift the digits to the appropriate positions
while (isdigit(*++p))
n = n * 10U + (unsigned) (*p - '0');
printf("%u\n", n); // We have finished parsing the integer, print it
}
}
Using atoi can also work, but it will require two passes over each integer: one in atoi itself and another one to move past the integer in the string you're parsing.
The function strtol allows you to pass a pointer to your pointer which is set to one place after the read integer, which avoids the issue. You can use this to advance the pointer. In this code example, the pointer is either advanced manually or by strtol:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char busy[30] = {"this is; it was; 163; 234;;"};
for (char *p = busy; *p; )
if (isdigit(*p))
printf("%ld\n", strtol(p, &p, 10));
else
++p;
}
Another alternative, without the use of isdigit:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char busy[30] = {"this is; it was; 163; 234;;"};
for (char *p = busy; *p; )
{
char *end;
long n = strtol(p, &end, 10);
if (p != end) // Pointer was advanced, so an integer was read
{
printf("%ld\n", n);
p = end;
}
else // Pointer was not advanced, do so manually
++p;
}
}
I need ideas for a recursive code that deletes a specific char in a string, and move all the other sting chars together
for Example :
"the weather is cloudy"
the entered char is 'e':
result :
"th wathr is cloudy"
I really don't have any idea how to start, thanks for the help.
#include <stdio.h>
void remove_impl(char* s, char c, char* d) {
if (*s != c) {
*d++ = *s;
}
if (*s != '\0') {
remove_impl(++s, c, d);
}
}
void remove(char* s, char c) {
remove_impl(s, c, s);
}
int main() {
char s[] = "the weather is cloudy";
remove(s, 'e');
puts(s);
}
How it works? Consider remove_impl. s is the original string, c is the character to be deleted from s, d is the resulting string, into which the characters of s, not equal to c, are written. Recursively iterates through the characters of s. If the next character is not equal to c, then it is written in d. The recursion stop point is the condition of checking that the end of s is reached. Since it is necessary to modify the source string, the wrapper is implemented (remove) in which as d, the original string (s) is passed.
An easy way to do it is to loop over the string and add any letter that doesn't match the unwanted letter.
Here's a demonstration:
char *source = "the weather is cloudy";
int source_len = strlen(source);
char *target = (char *)calloc(source_len, sizeof(char));
int target_len = 0;
char to_remove = 'e';
for(int i = 0; i < source_len; i++)
{
if(source[i] != to_remove)
{
target[target_len++] = source[i];
}
}
puts(target); // Output "th wathr is cloudy" in the console
My turn to make a proposal ! I add a assert test and use existing functions (strchr and strcpy).
#include <string.h>
#include <stdio.h>
#include <assert.h>
int removeChar(char *str, char chr)
{
assert(str != 0); // Always control entry !
char *str_pnt = strchr(str, chr);
if (str_pnt) {
strcpy(str_pnt, str_pnt+1);
removeChar(str_pnt, chr);
}
}
void main (void)
{
char str[] = "the weather is cloudy";
char char_to_delete = 'e';
removeChar(str, char_to_delete);
puts(str);
}
This can be done in many ways. What i am thinking right now is store not Allowed char array which going to filter which char should show or not. Something like following..
#include <stdio.h>
#include <string.h>
// Global Scope variable declaration
int notAllowedChar[128] = {0}; // 0 for allowed , 1 for not allowed
char inputString[100];
void recursion(int pos, int len) {
if( pos >= len ) {
printf("\n"); // new line
return;
}
if( notAllowedChar[inputString[pos]]) {// not printing
recursion( pos + 1 , len );
}
else {
printf("%c", inputString[pos]);
recursion( pos + 1 , len );
}
}
int main() {
gets(inputString); // taking input String
printf("Enter not allowed chars:: "); // here we can even run a loop for all of them
char notAllowed;
scanf("%c", ¬Allowed);
notAllowedChar[notAllowed] = 1;
int len = strlen(inputString);
recursion( 0 , len );
}
How this work
Lets say we have a simple string "Hello world"
and we want l should be removed from final string, so final output will be "Heo word"
Here "Hello world" length is 11 chars
before calling recursion function we make sure 'l' index which is 108 ascii values link 1 in notAllowedChar array.
now we are calling recursion method with ( 0 , 11 ) value , In recursion method we are having mainly 2 logical if operation, first one is for base case where we will terminate our recursion call when pos is equal or more than 11. and if its not true , we will do the second logical operation if current char is printable or not. This is simply just checking where this char is in notAllowedChar list or not. Every time we increase pos value + 1 and doing a recursion call, and finally when pos is equal or more than 11 , which means we have taken all our decision about printing char or not our recursion will terminate. I tried assign variable with meaningful name. If you still not understand how this work you should go with simple recursion simulation basic ( search in youtube ) and also you should try to manually debug how value is changing in recursion local scope. This may take time but it will be worthy to understand. All the very best.
#include <stdio.h>
/**
* Returns the number of removed chars.
* Base case: if the current char is the null char (end of the string)
* If the char should be deleted return 1 + no of chars removed in the remaining string.
* If it's a some other char simply return the number of chars removed in the remaining string
*/
int removeCAfterwardsAndCount(char* s,char c){
if((*s) == '\0'){
return 0;
}
if((*s) == c){
int noOfChars = removeCAfterwardsAndCount(s+1,c);// s+1 means the remaining string
s[noOfChars] = *s; // move the current char (*s) noOfChars locations ahead
return noOfChars +1; // means this char is removed... some other char should be copied here...
}
else{
int noOfChars = removeCAfterwardsAndCount(s+1,c);
s[noOfChars ] = *s;
return noOfChars ; // means this char is intact ...
}
}
int main()
{
char s[] = "Arifullah Jan";
printf("\n%s",s);
int totalRemoved = removeCAfterwardsAndCount(s,'a');
char *newS = &s[totalRemoved]; // the start of the string should now be originalPointer + total Number of chars removed
printf("\n%s",newS);
return 0;
}
Test Code Here
To avoid moving the chars using loops. I am just moving the chars forward which creates empty space in the start of the string. newS pointer is just a new pointer of the same string to eliminate the empty/garbage string.
#include <stdio.h>
void RemoveChar(char* str, char chr) {
char *str_old = str;
char *str_new = str;
while (*str_old)
{
*str_new = *str_old++;
str_new += (*str_new != chr);
}
*str_new = '\0'; }
int main() {
char string[] = "the weather is cloudy";
RemoveChar(string, 'e');
printf("'%s'\n", string);
return 0; }
#include <stdio.h>
#include <string.h>
char *remove_char(char *str, int c)
{
char *pos;
char *wrk = str;
while((pos = strchr(wrk, c)))
{
strcpy(pos, pos + 1);
wrk = pos;
}
return str;
}
int main()
{
char str[] = "Hello World";
printf(remove_char(str, 'l'));
return 0;
}
Or faster but mode difficult to understand version:
char *remove_char(char *str, int c)
{
char *pos = str;
char *wrk = str;
while(*wrk)
{
if(*wrk == c)
{
*wrk++;
continue;
}
*pos++ = *wrk++;
}
*pos = 0;
return str;
}
Both require the string to be writable (so you cant pass the pointer to the string literal for example)
I have a string of 80 chars (line from .txt file)
Somewhere at the end of the string I have numbers or strings or chars and "," (comma) between them. I need to delete these spaces around "," so I will be able to get them by strtok().
Any ideas ?
For example :
String : " name: today 12 ,r ,ab, 5 , seven"<br>
I need : " name: today 12,r,ab,5,seven"
You can apply this algorithm ::
Find the element , in this case a space.
Replace the element with an element of your choice, in this case an empty character.
This function might come handy for replacing any character to a string. You might add the char *replace function as a snippet and use it later for similar purposes.
char *replace(const char *the_input_string, char the_character,
const char *replacing_string)
{
int count = 0;
const char *t;
for(t=the_input_string; *t; t++)
count += (*t == the_character);
size_t rlen = strlen(replacing_string);
char *res = (char*)malloc(strlen(the_input_string) + (rlen-1)*count + 1);
char *ptr = res;
for(t=the_input_string; *t; t++)
{
if(*t == the_character)
{
memcpy(ptr, replacing_string, rlen);
ptr += rlen;
}
else
*ptr++ = *t;
}
*ptr = 0;
return res;
}
Driver Program ::
int main(int argc, char const *argv[])
{
const char *s = replace("name: today 12 ,r ,ab, 5 , seven", ' ', "");
printf("%s\n", s);
return 0;
}
Please refer to this link and the code might be verisimilar but use the above code as the solution mentioned there might throw some errors or warnings.
Because the resulting string will be shorter then the original string, you can do the replacement in place: When you find a comma, copy it and skip the following space. To treat the space before the comma, keep track of the first space after the last non-space character and skip that, too if necessary:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
void remspc(char *str)
{
char *first = str; // dest. char after last non-space
char *q = str; // destination pointer
// skip leading white space
while (isspace((unsigned char) *str)) str++;
while (*str) {
if (*str == ',') {
q = first; // skip space before comma
*q++ = *str++;
first = q;
// skip space after comma
while (isspace((unsigned char) *str)) str++;
} else {
// remember last non-space
if (!isspace((unsigned char) *str)) first = q + 1;
*q++ = *str++;
}
}
*first = '\0';
}
int main(void)
{
char str[] = " name: today 12, r ,ab, , 5 , seven";
remspc(str);
puts(str);
return 0;
}
This solution will run commas that are separated by white space together, which may lead to problems with strtok, because it will consider stretches of commas as a single delimiter.
You may give this a try!
Replace with your code where necessary.
#include <stdio.h>
#include <stdlib.h>
int main()
{ int i;
char line[] = "name: today 12 ,r ,ab, 5 , seven";
int length = strlen(line);
char line2[length];
for(i = 0; i<length; i++) {
if(!isspace(line[i])) {
line2[i] = line[i];
}
}
for(i = 0; i<length; i++){
printf("%c", line2[i]);
}
return 0;
}
Basically, I want to display the words and their number of occurrences in a string. It can be both case sensitive and vice-versa.
For e.g if the input string is "Hello World How are you Hello how", the output should be:
Hello,2
World,1
How,2
are,1
you,1
I am not able to figure out the logic for this yet; any help?
Use
fgets()
strtok_r()
strcmp()
Check these three APIs. Figure out the code-to-write, implement, run into issues, come back and we'll be here to help.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
bool eq(const char *s, const char *w, char ignore_case){
char si, wi;
while(*w && !isspace(*w)){
if(ignore_case != 'n'){
si = tolower(*s++);
wi = tolower(*w++);
} else {
si = *s++;
wi = *w++;
}
if(si != wi)
return false;
}
return !*s || isspace(*s);
}
char *next_word(char *w){
while(*w && !isspace(*w))
++w;
if(!*w)
return w;
while(isspace(*w))
++w;
return w;
}
int main() {
char ignore_case = 'n';
char *word, *str;
char string[128];
printf("ignore case ?(y/n):");
scanf("%c", &ignore_case);
printf("input string : ");
scanf(" %127[^\n]", string);
str = string;
while(*str){
int counter = 1;
word = next_word(str);//skip first word
while(*word){
char *p = NULL;
if(eq(str, word, ignore_case)){
p = word;
++counter;
}
word = next_word(word);//move to next word top
if(p)
memset(p, ' ', word - p);//clear already match word
}
word = str;
str = next_word(str);
while(*word && !isspace(*word))
putchar(*word++);
printf(",%d\n", counter);
}
return 0;
}
Here is a program to accept a:
Sentence from a user.
Word from a user.
How do I find the position of the word entered in the sentence?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char sntnc[50], word[50], *ptr[50];
int pos;
puts("\nEnter a sentence");
gets(sntnc);
fflush(stdin);
puts("\nEnter a word");
gets(word);
fflush(stdin);
ptr=strstr(sntnc,word);
//how do I find out at what position the word occurs in the sentence?
//Following is the required output
printf("The word starts at position #%d", pos);
return 0;
}
The ptr pointer will point to the beginning of word, so you can just subtract the location of the sentence pointer, sntnc, from it:
pos = ptr - sntnc;
Just for reference:
char saux[] = "this is a string, try to search_this here";
int dlenstr = strlen(saux);
if (dlenstr > 0)
{
char *pfound = strstr(saux, "search_this"); //pointer to the first character found 's' in the string saux
if (pfound != NULL)
{
int dposfound = int (pfound - saux); //saux is already pointing to the first string character 't'.
}
}
The return of strstr() is a pointer to the first occurence of your "word", so
pos=ptr-sntc;
This only works because sntc and ptr are pointers to the same string. To clarify when I say occurence it is the position of the first matching char when the matching string is found within your target string.
You can use this simple strpos modification
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strpos(char *haystack, char *needle, int offset);
int main()
{
char *p = "Hello there all y'al, hope that you are all well";
int pos = strpos(p, "all", 0);
printf("First all at : %d\n", pos);
pos = strpos(p, "all", 10);
printf("Second all at : %d\n", pos);
}
int strpos(char *hay, char *needle, int offset)
{
char haystack[strlen(hay)];
strncpy(haystack, hay+offset, strlen(hay)-offset);
char *p = strstr(haystack, needle);
if (p)
return p - haystack+offset;
return -1;
}
For some reasons I was having trouble with strstr(), and I also wanted index.
I made this function to find the position of substring inside a bigger string (if exists) otherwise return -1.
int isSubstring(char * haystack, char * needle) {
int i = 0;
int d = 0;
if (strlen(haystack) >= strlen(needle)) {
for (i = strlen(haystack) - strlen(needle); i >= 0; i--) {
int found = 1; //assume we found (wanted to use boolean)
for (d = 0; d < strlen(needle); d++) {
if (haystack[i + d] != needle[d]) {
found = 0;
break;
}
}
if (found == 1) {
return i;
}
}
return -1;
} else {
//fprintf(stdout, "haystack smaller\n");
}
}
My comment to the ORIGINAL post in this thread:
This declaration is INCORRECT:
char sntnc[50], word[50], *ptr[50];
C code would not even compile : it will fail on this line:
ptr = strstr(sntnc,word);
So the line shall be changed to :
char sntnc[50], word[50], *ptr;
And you do NOT need memeory allocated to 'ptr string'. You just need a pointer to char.