I am trying to rewrite this code written in C ++ in C (SI). The code does the following: reads str2 if it finds * reads str1 from the position * to the nearest < then adds ,

Result: Test_Value, 564, Test_Value2,456, Test_Value3,123,

int main() { std::string make_string{}; std::string final_string{}; std::string str1("<tr> <th>Test_Value</th> <th>564</th> </tr><tr> <th>Test_Value2</th> <th>456</th> </tr><tr> <th>Test_Value3</th> <th>123</th> </tr>"); std::string str2("<tr> <th>*</th> <th>*</th> </tr><tr> <th>*</th> <th>*</th> </tr><tr> <th>*</th> <th>*</th> </tr>"); size_t i = 0; i = str2.find("*", i); int position = i; auto count = 0; while (true) { while (str1[position] != '<') //читаем от позиции * до позицици < { make_string += str1[position]; // сохранить в переменную position++; // увеличить позицию на 1 } // повторить цикл i = str2.find('*', i + 1); // найти позицию следующей звезды if (i > str1.length()) // если звездочек больше нет, выйти из цикла break; final_string += make_string + ','; //записать в основную строку и поставить запятую make_string.clear(); // очистить временную строку count += 2; position = i + (final_string.length() - count); // вычисляем позицию для следующей итерации так: позиция следующей звездочки известна (20) прибавим длину записанных символов и вычтем * и , } final_string += make_string; cout << final_string << endl; return 0; } 

Redid it like this for SI.

 #include <stdio.h> #include <string.h> int main(void) { char *make_string = NULL; char *final_string = NULL; char *str1[] = "<tr> <th>Test_Value</th> <th>564</th> </tr><tr> <th>Test_Value2</th> <th>456</th> </tr><tr> <th>Test_Value3</th> <th>123</th> </tr>"; char *str2[] = "<tr> <th>*</th> <th>*</th> </tr><tr> <th>*</th> <th>*</th> </tr><tr> <th>*</th> <th>*</th> </tr>"; size_t i = 0; char *ptr = strchr(str2, '*'); i = ptr - str2; // нашли позицию * int position = i; int count = 0; for (ptr = str2; *ptr != '\0'; ptr++) { // читаем строку посимвольно передвигаем указатель if (*ptr == '*') { // нашли звезду -> установили указатель на позицию * ---> } memset(&make_string, '\0', sizeof(char*)); //make_string = ""; } strcat(final_string, make_string); //final_string += make_string; printf("%s\n",final_string); return 0; } 

Questions: ---> here you need to read from position * to <in str1.

How to move the pointer to the same position where it is in str2?

  • To begin with, strchr returns a pointer, not a position (i.e. it needs to be recalculated). The star after while can be searched for by him. Naturally, if you accumulate characters in make_string , then realloc needed, but the fact is that you don’t need to accumulate them. It is enough to memorize the positions of the beginning and end of the copied text in str1[] , then you can add it to the final_string (this is where realloc is needed) (however, if you have an idea of ​​the size of str1, then it may be better to allocate memory for final_string once, in the very beginning). And do not make stupid calls to strcat and strlen inside cycles - avp
  • Judging by the strcat in your code, you already know that you cannot concatenate in the C line with + or += . Why then in the loop do you still have some sort of make_string += ... ? - AnT
  • Because I can not alter the while loop. That is the question. - GarfieldCat
  • @avp Yes, I counted the position instead of the pointer. Ie now I need to move the pointer to '<' (how to do it?) And make strncpy? - GarfieldCat
  • @avp unfortunately, it's almost impossible to say the size of final_string, you need to do realloc. - GarfieldCat

2 answers 2

 #include <string.h> #include <stdlib.h> int main(void) { char *make_string = NULL; char *final_string = NULL; char str1[] = "<tr> <th>Test_Value</th> <th>564</th> </tr><tr> <th>Test_Value2</th> <th>456</th> </tr><tr> <th>Test_Value3</th> <th>123</th> </tr>"; char str2[] = "<tr> <th>*</th> <th>*</th> </tr><tr> <th>*</th> <th>*</th> </tr><tr> <th>*</th> <th>*</th> </tr>"; size_t i = 0; size_t i2=0; size_t str1_length=strlen(str1); size_t str2_length=strlen(str2); size_t final_string_length=0; //указатель на * в str2 char *ptr2 = strchr(str2, '*'); //указатель на < в str1 char *ptr1=NULL; size_t position = ptr2-str2; size_t count = 0; while (ptr2!=NULL) { // пока находится указатель на звёздочку в str2 //позиция * i=ptr2-str2; //ищем < в str1 if(position<str1_length) { ptr1=strchr(str1+position,'<'); }else ptr1=NULL; if(ptr1!=NULL)//если найден < { size_t substr_length=ptr1-(str1+position); //position=position+substr_length; make_string=(char*)realloc(make_string,substr_length+1); strncpy(make_string,str1+position,substr_length); make_string[substr_length]='\0'; //TODO:соединить с final_string size_t comma_length=1; if(final_string==NULL) comma_length=0; final_string=(char*)realloc(final_string,final_string_length+substr_length+1+comma_length); final_string[final_string_length]='\0'; if(comma_length) final_string=strcat(final_string,","); final_string=strcat(final_string,make_string); final_string_length=final_string_length+substr_length+1; //увеличиваем позицию начала поиска звёздочки i=i+1; //ищем следующую * if(i<str2_length) { ptr2 = strchr(str2+i, '*'); i=ptr2-str2; count=count+2; position = i + (final_string_length - count); }else ptr2=NULL; }else ptr2=NULL;//дальше искать нет смысла } //добавляем последнюю запятую final_string=(char*)realloc(final_string,final_string_length+1); final_string[final_string_length]='\0'; final_string=strcat(final_string,","); printf("%s\n",final_string); //TODO: освободить память free(make_string); free(final_string); return 0; } 

More robust to the spaces from the first and second line algorithm:

 #include <string.h> #include <stdlib.h> int main(void) { char *make_string = NULL; char *final_string = NULL; size_t final_string_length=0; char str1[] = "<tr> <th>Test_Value_Very_Big_Big_value_VALUE</th> <th>564</th> </tr><tr> <th>Test_Value2</th> <th>456</th> </tr > <tr> <th>Test_Value3</th> <th>123</th> </tr>"; char str2[] = "< tr > < th >* </th> <th >*</th> </tr > <tr> <th>*</th> <th>* </th> </tr> <tr> <th> *</th> <th>* </th> </tr>"; size_t str1_length=strlen(str1); size_t str2_length=strlen(str2); size_t substr_length=0; int more1_count=0; int more2_count=0; char *more1_last=NULL;//позиция последнего '>' в str1 char *less1=NULL;//позиция '<' в str1 int i2=0;//текущая позиция в str2 int i1=0;//текущая позиция в str1 size_t comma_length=0; for(i2=0;i2<str2_length;++i2) { switch(str2[i2]) { case '>': more2_count++; if(more1_count<more2_count) { more1_last=strchr(str1+i1,'>'); if(!more1_last) break;//соответствующий '>' не найден, заканчиваем перебор i1=more1_last-str1+1;//передвигаем позицию в str1 на знак за '>' more1_count++; } break; case '*': if(!more1_last) break;//не было '>' в str1 - некорректные входные данные less1=strchr(more1_last,'<'); if(!less1) break;//нет '<' str1 в str1 - некорректные входные данные substr_length=less1-more1_last-1; make_string=(char*)realloc(make_string,substr_length+1); strncpy(make_string,more1_last+1,substr_length); make_string[substr_length]='\0'; //TODO:соединить с final_string if(final_string) comma_length=1; final_string=(char*)realloc(final_string,final_string_length+substr_length+1+comma_length); final_string[final_string_length]='\0'; if(comma_length) final_string=strcat(final_string,","); final_string=strcat(final_string,make_string); final_string_length=final_string_length+substr_length+1; break; } } //добавляем последнюю запятую final_string=(char*)realloc(final_string,final_string_length+1); final_string[final_string_length]='\0'; final_string=strcat(final_string,","); printf("%s\n",final_string); //TODO: освободить память free(make_string); free(final_string); return 0; } 
  • It is not known how many letters and how many numbers, so additional spaces are not suitable. - GarfieldCat
  • @GarfieldCat already realized that a slightly different algorithm. - MindCleaner
  • @GarfieldCat see the new version. Works with source data. - MindCleaner
  • If you make the line like this: char str1 [] = "<tr> <th> Test_Value_Very_Big_Big_value_VALUE </ th> <th> 564 </ th> </ tr> <tr> <th> Test_Value2 </ th> <th> 456 < / th> </ tr> <tr> <th> Test_Value3 </ th> <th> 123 </ th> </ tr> "; then it’s like this: Test_Value_Very_Big_Big_value_VALUE, e2, / tr>, est_Value3, - GarfieldCat
  • @GarfieldCat I agree with you that the new position to start searching for an asterisk was wrong. Corrected. Simple incrementing by one leads to the conclusion of a correct result for the one specified in the comment str1. It remained from the algorithm, where I finished off the second line with spaces. - MindCleaner
 avp@avp-ubu1:hashcode$ gcc obtain_text.c -Wall && ./a.out Test_Value,564,Test_Value2,456,Test_Value3,123, avp@avp-ubu1:hashcode$ cat obtain_text.c 

Corrected a little past version and added comments

 #include <stdio.h> #include <stdlib.h> // тут realloc-ом собираем результат (кусочки текста и запятые) struct result { char *str; int capacity, // сколько памяти всего выделено size; // сколько байт накоплено в str }; // добавим символ в конец накапливаемого результата // завершающий 0 не заносим, поэтому его надо добавлять на верхнем уровне static inline char * add_char (struct result *r, char c) { if (r->size >= r->capacity - 1) if (!(r->str = realloc(r->str, r->capacity *= 2))) return 0; // ENOMEM r->str[r->size++] = c; return r->str; } // пропустим заданное число символов // скопируем символы текста до завешающего `<` в результат // при пропуске и копировании анализируем источник на завершающий 0 // возвращаем адрес найденного `<` или завершающего 0-ля, // т.е. адрес, с которого начинается поиск следующего кусочка результата static const char * add_text (struct result *r, const char *src_text, int nskip) { for (; nskip && *src_text; nskip--) src_text++; while (*src_text && *src_text != '<') if (!add_char(r, *src_text++)) return 0; // out of memory return src_text; } // returns comma separeted text in dynamic memory // or NULL on ENOMEM char * obtain_text (const char *text, const char *pattern) { int nskip; struct result result = {malloc(16), 16, 0}; if (!result.str) return 0; // ENOMEM for (nskip = 0; *pattern; nskip++, pattern++) if (*pattern == '*') { // найдено начало очередного фрагмента текста в nskip символах от text if (!(text = add_text(&result, text, nskip)) || !add_char(&result, ',')) return 0; nskip = -1; } // завершим изготовление результата // (add_char(), добавлявший символы, не записывает завершающий 0) result.str[result.size] = 0; return realloc(result.str, result.size + 1); } int main (int ac, char *av[]) { char str1[] = "<tr> <th>Test_Value</th> <th>564</th> </tr><tr> <th>Test_Value2</th> <th>456</th> </tr><tr> <th>Test_Value3</th> <th>123</th> </tr>"; char str2[] = "<tr> <th>*</th> <th>*</th> </tr><tr> <th>*</th> <th>*</th> </tr><tr> <th>*</th> <th>*</th> </tr>"; char *str = obtain_text(str1, str2); // Test_Value,564,Test_Value2,456,Test_Value3,123, if (str) { puts(str); free(str); } else exit((perror("obtain_text"), 1)); return 0; }