Extract all numbers of N digits from a string in C - c

I want to get all numbers from a specific string but, these numbers could be more than one digit long as (15, 587, ... exc). Here is what I did "my own code":
int firstIndxOfNumb(char* str, int startIndx, int len) {
int i, val;
i = startIndx;
while (str[i] && i < len) {
val = str[i];
if (isdigit(val))
return i;
i++;
}
return -1;
}
int lastIndxOfNumb(char* exp, int len, int indx1){
int i, curr;
for(i = indx1; i < len; i++){
curr = exp[i];
if(!isdigit(curr)){
return --i;
}
}
return 0;
}
int getNumb(char* exp, int len, int* indx1){
int indx2 = lastIndxOfNumb(exp, len, *indx1);
printf("indx1:%d\tindx2:%d\n", *indx1, indx2);
char temp[indx2-*indx1];
strncpy(temp, exp+*indx1, (size_t) (indx2-*indx1+1));
*indx1 = firstIndxOfNumb(exp, indx2+1, len);
return atoi(temp);
}
void main() {
char *s = "())(15*59";
int len = strlen(s);
int indx1;
indx1 = firstIndxOfNumb(s, 0, len);
printf("%d\n", getNumb(s, len, &indx1));
printf("\n%d", getNumb(s, len, &indx1));
}
And the goal is getting the two numbers (15, 59). The first call was okay but, the second is not "infinite-loop" with values index1:7 okay index2:0 isn't okay! Can you help me to make it working .....
The values are printed by printf(..); in getNum(); function ....

getNumb can be simplified as follows.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int getNumb(char **sp){
char *p = *sp;
while(*p && !isdigit((unsigned char)*p))//skip not digit
++p;
if(!*p)
return -1;//not find numbers (Don't include negative numbers as extract numbers)
int ret = strtol(p, &p, 10);
*sp = p;
return ret;
}
int main(void) {
char *s = "())(15*59";
char *sp = s;
printf("%d\n", getNumb(&sp));
printf("%d\n", getNumb(&sp));
}
When it contains a negative number.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
bool getNum(char **sp, int *v /* out */){
char *p = *sp;
while(*p && !isdigit((unsigned char)*p) && (*p!='-' || !isdigit((unsigned char)p[1])) )//skip not number
++p;
if(!*p)
return false;//not find numbers
*v = strtol(p, &p, 10);
*sp = p;
return true;
}
int main(void) {
char *s = "())(15*59+++-123,-2)";
char *sp = s;
int v;
while(getNum(&sp, &v))
printf("%d\n", v);
}

Related

C string manipulation for removing xx:xx:xx:xx:xx:xx

I have a problem removing a substring xx:xx:xx:xx:xx:xx from one main string. Here is the background info for the problem:
in a function void funA():
void funA(const char* sth){
if (sth == THINGA){
// do A;
}
else if (sth == THINGB){
// do B;
}
eles{
// do C;
}
log_status("current status: - %s", sth);
}
sth is a string contains a substring in the format of xx:xx:xx:xx:xx:xx where x is either a number or a letter. The substring has a space in front of it but might not have one at the end of the string. I need to obfuscate this substring with a *. Since only the substring has :, I made a helper function to locate the first : and the last : and remove 2 characters before it. Delete the last 2 characters and append a *. I think this way is most the best solution. So I'm wondering if there are any more efficient design of a helper function aka a helper function has shorter runtime and uses less memory. Since the substring xx:xx:xx:xx:xx:xx has a very distinguish format, the only easier way I can think of is to do a string match to find the substring and then replace it with a *. I'm open to other more innovative way though.
#ifndef PARSER_STACK_H_INCLUDED
#define PARSER_STACK_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PATTERN_LEN 18
typedef struct{
unsigned int start;
unsigned int finish;
}index;
void remove_str_pattern(char *original, char *extract, unsigned int start, unsigned int finish);
void splitter(char *x, index *index_SF);
unsigned int count_points(const char *x);
void obscure(char *str, index index_SF);
char* return_obscure_string(char *str);
char* return_pattern(char *str);
char* return_pattern(char *str){
index index_SF = {0,0};
char *str_export = calloc(PATTERN_LEN, sizeof(char));
char *tmp = calloc(sizeof(str)/sizeof(char), sizeof(char));
strcpy(tmp, str);
splitter(str, &index_SF);
obscure(tmp, index_SF);
remove_str_pattern(str, str_export, index_SF.start, index_SF.finish);
return str_export;
}
char* return_obscure_string(char *str){
index index_SF = {0,0};
char *str_export = calloc(PATTERN_LEN, sizeof(char));
char *tmp = calloc(sizeof(str)/sizeof(char), sizeof(char));
strcpy(tmp, str);
splitter(str, &index_SF);
obscure(tmp, index_SF);
remove_str_pattern(str, str_export, index_SF.start, index_SF.finish);
return tmp;
}
void obscure(char *str, index index_SF){
for(unsigned int i = index_SF.start; i < index_SF.finish+1; ++i){
if(str[i] != ':'){
str[i] = '*';
}
}
}
void splitter(char *x, index *index_SF){
for(unsigned int i = 0, tmp = 0; i < strlen(x); ++i){
if(x[i] == ':'){
++tmp;
if(tmp == 1){
index_SF->start = i-2;
}else{
if(tmp == 5){
index_SF->finish = i+2;
}
}
}
}
}
unsigned int count_points(const char *x){
int c = 1;
for(unsigned int i = 0; i < strlen(x); ++i){
if((x[i] == ':' && x[i+2] == ':') || (x[i] == ':' && x[i-2] == ':')){
++c;
}
}
return c;
}
void remove_str_pattern(char *original, char *extract, unsigned int start, unsigned int finish){
for(unsigned int i = start, j = 0; i < finish+1; ++i, ++j){
extract[j] = original[i];
}
}
#endif // PARSER_STACK_H_INCLUDED
That is my personal header file for your request, create header file with this code and try it ! :D
Two "main" functions of this file are.
1. char* return_obscure_string(char *str);
For return original string with obscured sub-string..
2. char* return_pattern(char *str);
For return pattern value from a string..
Good Luck Man !
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PATTERN_LEN 18
typedef struct{
unsigned int start;
unsigned int finish;
}index;
void remove_str_pattern(char *original, char *extract, unsigned int start, unsigned int finish);
void splitter(char *x, index *index_SF);
unsigned int count_points(const char *x);
void obscure(char *str, index index_SF);
void main(){
index index_SF = {0,0};
char *origin = "this is first try for me in stack aa:bb:22:44:55:66 overflow...";
char *str_export = calloc(PATTERN_LEN, sizeof(char));
char *tmp = calloc(sizeof(origin)/sizeof(char), sizeof(char));
strcpy(tmp, origin);
splitter(origin, &index_SF);
obscure(tmp, index_SF);
remove_str_pattern(origin, str_export, index_SF.start, index_SF.finish);
printf("start index: %u finish index: %u\n", index_SF.start, index_SF.finish);
printf("obscured string %s\n", tmp);
printf("original str: %s\n", origin);
printf("pattern: %s\n", str_export);
}
void obscure(char *str, index index_SF){
for(unsigned int i = index_SF.start; i < index_SF.finish+1; ++i){
if(str[i] != ':'){
str[i] = '*';
}
}
}
void splitter(char *x, index *index_SF){
for(unsigned int i = 0, tmp = 0; i < strlen(x); ++i){
if(x[i] == ':'){
++tmp;
if(tmp == 1){
index_SF->start = i-2;
}else{
if(tmp == 5){
index_SF->finish = i+2;
}
}
}
}
}
unsigned int count_points(const char *x){
int count = 1;
for(unsigned int i = 0; i < strlen(x); ++i){
if((x[i] == ':' && x[i+2] == ':') || (x[i] == ':' && x[i-2] == ':')){
++count;
}
}
return count;
}
void remove_str_pattern(char *original, char *extract, unsigned int start, unsigned int finish){
for(unsigned int i = start, j = 0; i < finish+1; ++i, ++j){
extract[j] = original[i];
}
}

String length always 0

I am trying to teach myself C,so I am writing a program to see if a string is present at the end of another string.
#include <stdio.h>
#include <stdlib.h>
int containsAtEnd(char *s, char *t);
int strlen(char *s);
int main()
{
char *x = "tacocat";
char *y = "bol";
printf("%d\n", strend(x, y));
getchar();
return 0;
}
int strlen(char *s)
{
int i;
for (i = 0; i != '\0'; ++i)
;
printf("%d", i);
return i;
}
int containsAtEnd(char *s, char *t)
{
int tlen = strlen(*t);
int slen = strlen(*s);
int i = 0;
s += slen - tlen;
while ((*s == *t) && *s != '\0')
i++; s++; t++;
if (i < (tlen-1))
return 0;
else
return 1;
}
Yet, regardless of the strings given in the main function, "001" is always printed, indicating that the length of both the strings in 0 and the second string is present in the first.
Please try if the following code can help you. I would also advice you to use an IDE or an analysis program that tells you about taking pointer from integer without a cast and conditions that are always true (or always false).
#include <stdio.h>
int containsAtEnd(char *s, char *t);
int strlen(char *s);
int strlen(char *s)
{
int i;
for (i = 0; s[i] != '\0'; ++i)
;
printf("%d", i);
return i;
}
int containsAtEnd(char *s, char *t)
{
int tlen = strlen(t);
int slen = strlen(s);
int i = 0;
s += slen - tlen;
while ((*s == *t) && *s != '\0') {
i++; s++; t++;
}
if (i < (tlen-1))
return 0;
else
return 1;
}
int main()
{
char *x = "tacocat";
char *y = "bol";
printf("%d\n", containsAtEnd(x, y));
char *x2 = "foobarbaz";
char *y2 = "bar";
printf("%d\n", containsAtEnd(x2, y2));
getchar();
return 0;
}

merge two strings of different sizes in C

How can I merge character by character two strings of different sizes to the n-th element of A and m-th element of B. I can easily do it when they have the same size (assuming here n=m). But cannot figure out how to handle this exception.
My working zip code is as follows:
char * zip(char *A, char *B, int n)
{
char *C;
int i;
C = malloc((2*n) * sizeof *A);
for(i=0; i<n; i++) {
C[(2*i)]=A[i];
C[(2*i)+1]=B[i];
}
return C;
}
But instead to pass just int n, I would like to pass also int m where n is to merge the n first elements of A and the m first elements of B. Hence passing the following input to the new_zip(char *A, char *B, int n, int m). A="rslxyzkw"; B="eutingxyz";n=3; m=6, I would get "resulting".
like this:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char *new_zip(char *A, char *B, int n, int m){
assert(A != NULL && B != NULL && n >= 0 && m >= 0);
char *C = malloc(n + m + 1);//+1 for NUL
if(!C){
perror("malloc:");
return NULL;
}
int i = 0;
while(n + m > 0){
if(n > 0 && *A){
C[i++] = *A++;
--n;
}
if(m > 0 && *B){
C[i++] = *B++;
--m;
}
}
C[i] = 0;
return C;
}
int main (void){
char *result = new_zip("rslxyzkw", "eutingxyz", 3, 6);
printf("'%s'\n", result);
free(result);
return 0;
}
Instead of looping until a certain length you can loop until you run out of characters. C strings have a null character at the end so after you allocate the memory you can loop as long as both aren't a null character. All you need to do then is only add non-null characters to your output string.
#include <stdio.h> /* printf */
#include <stdlib.h> /* malloc, free */
#include <string.h> /* strlen */
char *zip(char *a, char *b)
{
char *c = malloc( (strlen(a)+strlen(b)+1) * sizeof(char) ), *p = c;
if(c)
{
while(*a || *b) /* while either string has characters */
{
if(*a) *p++ = *a++; /* add a character from a if non-null */
if(*b) *p++ = *b++; /* add a character from b if non-null */
}
*p='\0'; /* finish the string with a null character */
}
return c;
}
int main()
{
char *a = "This is a string";
char *b = "This is another longer string";
char *c = zip(a,b);
if(c)
{
printf("zip(%s,%s) = %s\n",a,b,c);
free(c);
}
return 0;
}
The following could work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* zip(char* A, char* B) {
char *C;
int k = 0;
C = (char*)malloc(strlen(A)+strlen(B)+1);
while (*A != '\0' || *B != '\0') {
if (*A != '\0') {
C[k++] = *A;
++A;
}
if (*B != '\0') {
C[k++] = *B;
++B;
}
}
C[k] = '\0';
return C;
}
int main() {
char *A = "123456", *B = "abcd", *C;
C = zip(A, B);
puts(C);
return 0;
}
The below code would work in the following way:
First do alternate merging from strings s1 and s2 based on the minimum value of m and n.
The second part would take care of appending the remaining elements either from s1 or from s2.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* merge (char *s1, char *s2, int m, int n)
{
char *s = (char *) malloc(m + n + 1);
int min = (m < n)? m: n;
int i = 0, j = 0, k = 0;
int count = 0;
/* Alternate merge from s1 and s2 to s*/
while (count < 2 * min) {
if (count % 2 == 0) {
s[k++] = s1[i++];
} else {
s[k++] = s2[j++];
}
count++;
}
/* Append the remaining elements from s1 or s2 to s*/
if (m > min) {
for (count = 0; count < m - min; count++) {
s[k++] = s1[i++];
}
} else if (n > min) {
for (count = 0; count < n - min; count++) {
s[k++] = s2[j++];
}
}
s[k++] = '\0';
return s;
}
int main()
{
char *s1 = "rslxyzkw";
char *s2 = "eutingxyz";
char *s = merge(s1, s2, 3, 6);
printf ("%s\n", s);
}

Code can't get an n-digit numbers from a string in C

I wanna ask how it can not get integer from a string
for example, here are my code:
int main() {
char str[] = "ababbababa-1998";
int nr = atoi(str);
printf("%d\n", nr);
return (EXIT_SUCCESS);
}
when running, it print out 0 but not 1998, how can I fix it ?
In your case you can use strtok.
int main() {
char str[] = "ababbababa-1998";
char * const first_part = strtok(str, "-");
if (first_part == NULL) {
return 1;
}
char * const second_part = strtok(NULL, "-");
if (second_part == NULL) {
return 1;
}
int nr = atoi(second_part);
printf("%d\n", nr);
return 0;
}
You can look at Why is there no strtoi in stdlib.h? for error check atoi.
Keep walking down str() until code finds something numeric using strtol().
int main() {
char str[] = "ababbababa-1998";
char *p = str;
char *endptr;
while (*p) {
long number = strtol(p, &endptr, 10);
// Was conversion successful?
if (endptr != p) {
printf("%ld\n", number);
return EXIT_SUCCESS;
}
p++;
}
puts("No conversion");
return EXIT_FAILURE;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define ASCII '0'
int
main(void) {
char const str[] = "ababbababa-1998";
int i, result = 0;
for (i = 0; str[i]; i++) {
if (isdigit(str[i])) {
result *= 10;
result += str[i] - ASCII;
}
}
printf("number = %d\n", result);
return 0;
}
If you want to extract all the numeric digits from a string you could use this function I created.
You will need these header files for this function to work.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void getNumbers(char data[]) {
int index = 0;
char current;
for( int i = 0; i < strlen(data); ++i ) {
current = data[i];
if (current >= 48 && current <= 57) {
data[index++] = current;
}
}
data[index] = '\0';
}
You can use the above function like this.
char foobar[] = "1A2B3C4D5E6F7G8H9I";
getNumbers(foobar);
printf("%s", foobar);
The above code will output 123456789

copying string by incrementing array in c

I am trying to search particular element in an array and copying to other.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main()
{
unsigned char a[16] = "1011\n23578A23\n\r";
unsigned char b[9];
unsigned char c[5];
unsigned char d[5] = "1011";
int i = 4;
memcpy(c,a,4);
printf("%s\n", c);
if(strcmp(c,d) == 0)
{
printf("\nEnter\n");
while(a[i] != '\r')
{
if(a[i] == '\n')
{
i = i+1;
printf("start copying\n");
memcpy(b,&a[i],8);
}
i = i+8;
}
}
}
But i am getting seg fault. Is my idea of increment is wrong?
You have to set the null terminator in c string.
memcpy(c,a,3);
c[4] = 0;
printf("%s\n", c);
#include <stdio.h>
#include <string.h>
int main(){
unsigned char a[16] = "1011\n23578A23\n\r";
unsigned char b[9] = {0};
unsigned char c[5] = {0};
unsigned char d[5] = "1011";
int i = 4;
memcpy(c,a,4);
printf("%s\n", c);
if(strcmp(c,d) == 0){
printf("\nEnter\n");
if(a[i] == '\n'){
i = i + 1;
printf("start copying\n");
memcpy(b, &a[i],8);
//printf("%s\n", b);
//i = i + 8;
}
}
}

Resources