LINUX.ORG.RU

в С строке не находится вторая «<» в цикле

 ,


0

1

Вот код, который смотрит на строку из массива lines_down и сравнивает её с lines_temp. Если находит звездочку, то выписывает значение и продолжает дальше пока не кончатся звездочки. Потом переходит к другой строке.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


char *substring(const char *str, size_t begin, size_t len) {
    if (str == 0 || strlen(str) == 0 || strlen(str) < begin ||
        strlen(str) < (begin + len))
        return 0;

    return strndup(str + begin, len);
}

int main() {
    char *make_string = NULL;
    char *final_string = NULL;
    char **lines_down = (char *[]){"<tr> <th>Test_Value_1</th> <th>4334</th> </tr>",
                              "<tr> <th>Test_Value_2</th> <th>5467</th> </tr>",
                              "<tr> <th>Test_Value_3</th> <th>34543</th> </tr>",
                              NULL
                             };
    char **lines_temp = (char *[]){"!#<tr> <th>*</th> <th>*</th> </tr>",
                              "!#<tr> <th>*</th> <th>*</th> </tr>",
                              "!#<tr> <th>*</th> <th>*</th> </tr>",
                              NULL
                             };

    char *substr_temp = NULL;
    size_t comma_length = 1;
    size_t final_string_length = 0;
    while (*lines_temp && *lines_down) {
        if (strstr(*lines_temp, "!#") != NULL) {
            substr_temp = substring(*lines_temp, 2, strlen(*lines_temp) - 2);
            size_t i = 0;
            size_t i2 = 0;
            size_t str1_length = strlen(*lines_down);
            size_t str2_length = strlen(substr_temp);
            char *ptr2 = strchr(substr_temp, '*'); //указатель на * в str2
            char *ptr1 = NULL; //указатель на < в str1

            size_t position = ptr2 - substr_temp;
            size_t count = 0;
            while (ptr2 != NULL) { // пока находится указатель на звёздочку в str2
                //позиция *
                i = ptr2 - substr_temp;
                //ищем < в str1
                if (position < str1_length) {
                    ptr1 = strchr(*lines_down + position, '<');
                } else ptr1 = NULL;
                if (ptr1 != NULL)//если найден <
                {
                    // ==========================================
                    // на четвертой итерации здесь копируется мусор, а потом Test_Value_3 вместо 5467
                    size_t substr_length = ptr1 - (*lines_down + position); // строка под звездочкой
                    make_string = realloc(make_string, substr_length + 1); // выделить память для подстроки плюс нулевой символ
                    strncpy(make_string, *lines_down + position, substr_length); // скопировать в make_string строку под звездочкой из исходной строки (lines_down + позиция *)
                    make_string[substr_length] = '\0'; // добавить строку под звездочкой в make_string

                    //скопировать в финальную строку и добавить запятую в конец
                    final_string = realloc(final_string, final_string_length + substr_length + comma_length + 1); // память - длина final_string + длина строки под звездочкой + запятая + нулевой символ
                    final_string[final_string_length] = '\0'; // добавить нулевой символ
                    final_string = strcat(final_string, make_string); // копируем make_string в final_string
                    final_string = strcat(final_string, ","); // добавляем запятую
                    final_string_length = final_string_length + substr_length + 1; // считаем новую длину строки final_string
                    i++; //увеличиваем позицию начала поиска звёздочки

                    if (i < str2_length) { //ищем следующую *
                        ptr2 = strchr(substr_temp + i, '*');
                        i = ptr2 - substr_temp;
                        count = count + 2;
                        position = i + (final_string_length - count);
                    } else ptr2 = NULL;
                } else ptr2 = NULL;//дальше искать нет смысла


            }
            //добавляем последнюю запятую
            final_string = realloc(final_string, final_string_length + 1);
            final_string[final_string_length] = '\0';
            final_string = strcat(final_string, ",");
        }

        ++lines_down;
        ++lines_temp;
    }
    printf("%s\n", final_string);
    return 0;
}

Результат работы программы: Test_Value_1,4334,Test_Value_2,Test_Value_3,,

Ожидаемый результат: Test_Value_1,4334,Test_Value_2,5467,Test_Value_3,34543,

На четвертом цикле position = 49 и сюда не попадает:

if (position < str1_length) {
    ptr1 = strchr(*lines_down + position, '<');

★★★★★

Портянку не читал, но бывает полезно пользоваться дебаггером.

DELIRIUM ☆☆☆☆☆ ()
Ответ на: комментарий от DELIRIUM

Я им и пользуюсь. Вконце написал что position = 49 и вот непонятно почему. Первая строка обрабатывается нормально, а последующие уже нет.

sniper21 ★★★★★ ()
Последнее исправление: sniper21 (всего исправлений: 2)

Для меня остается загадкой, как можно писать по-русски с ошибками, опечатками и пропусками букв, но надеяться, что при программировании на низкоуровневом ЯП проблем с невнимательностью и отсутствием концентрации не возникнет.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

Для меня остается загадкой, как можно писать по-русски с ошибками, опечатками и пропусками букв

Поправил

sniper21 ★★★★★ ()
size_t substr_length = ptr1 - (*lines_down + position); // строка под звездочкой

Насколько я знаю, так делать нельзя. Я конечно, могу ошибаться, но в арифметике указателей можно только вачитать и прибавлять к указателю числа, а не другие указатели.

Да и вообще, твой код можно переписать на нормальную индексацию. Потери производительности хоть немного значимой не будет, а читать станет возможно.

Aswed ★★★★★ ()
dron@gnu:~$ gcc myfind.c 
dron@gnu:~$ ./a.out 
Test_Value_1,334,
Test_Value_2,467,
Test_Value_3,4543,
dron@gnu:~$ cat myfind.c 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char * myfind(char * data, char * tpl, char * buffer, int buffer_size)
{
    int data_len = strlen(data);
    int buff_len = 0;
    int tpl_len = strlen(tpl);
    for (int i = 0, t = 0; i < data_len && t <tpl_len; ++i,++t)
    {
        if(data[i] != tpl[i] && tpl[t] == '*')
        {
            while(data[i] !='<' && i < data_len)
            {
                if(buff_len < buffer_size)
                {
                    buffer[buff_len++]=data[i++];
                };
            };
            if(buff_len+1 < buffer_size)
            {
                buffer[buff_len++]=',';
            };
        };
    };
    buffer[buff_len]='\0';
};

int main(int argc, char *argv[])
{
   char buffer[100];
   char data[][100] =
   {
       "<tr> <th>Test_Value_1</th> <th>4334</th> </tr>",
       "<tr> <th>Test_Value_2</th> <th>5467</th> </tr>",
       "<tr> <th>Test_Value_3</th> <th>34543</th> </tr>"
   };
   char tpl[][100]  = 
   {
       "<tr> <th>*</th> <th>*</th> </tr>",
       "<tr> <th>*</th> <th>*</th> </tr>",
       "<tr> <th>*</th> <th>*</th> </tr>"
   };

   myfind(data[0],tpl[0],buffer,99);
   printf("%s\n",buffer);

   myfind(data[1],tpl[1],buffer,99);
   printf("%s\n",buffer);
   
   myfind(data[2],tpl[2],buffer,99);
   printf("%s\n",buffer);

    return 0;
}
dron@gnu:~$ 

Deleted ()
Ответ на: комментарий от Aswed

Насколько я знаю, так делать нельзя.

Ошибаетесь. Если при вычитании берутся указатели от одной сущности с разными смещениями и разность положительна, то это и есть size_t — положительная разность смещений.

Ну и в общем виде, то что делать нельзя язык точно не позволит. На то что делать не рекомендуется найдётся соответствующая опция, включающая предупреждение об этом.

vodz ★★★★★ ()
Ответ на: комментарий от vodz

Ошибаетесь. Если при вычитании берутся указатели от одной сущности с разными смещениями и разность положительна, то это и есть size_t — положительная разность смещений.

Спасиб за уточнение

Ну и в общем виде, то что делать нельзя язык точно не позволит

Да ладно! Си и плюсы это UB верхом на UB.

Aswed ★★★★★ ()
Ответ на: комментарий от sniper21

Вконце написал что position = 49 и вот непонятно почему

Понятно почему — потому что говнокод с арифметикой указателей. Конкретно тут ты запутался с определением позиции в первой строке, забыв, что входных строк у тебя несколько, а выходная-то одна и через неё считать позицию для второй строки уже не получится.

redgremlin ★★★★★ ()
Ответ на: комментарий от Aswed

Всё совсем наоборот, арифметика указателей это аддрес-(аддрес+(смещение*разрядность)), но с обычным uint8_t можно без разрядности ибо байт...не всегда, но это экзотика

Deleted ()
Ответ на: комментарий от Aswed

Си и плюсы это UB верхом на UB

Именно. Если вам это запрещает религия, то это не в Си нельзя, это вас к Си — подпускать нельзя.

vodz ★★★★★ ()

вот она вся суть коддинга на Си/С++ когда тривиальная задача становится адовым поиком ошибок на пол дня

переписать твой код на джава/джаваскрипте/C# будет быстрее чем найдешь ошибку в этом коде

пиши на нормальных языках, для экономии времени

anonymous ()

Блин, если сравнивать строку с lines_temp, то можно сказать равна строка lines_temp или не равна. Представляешь, если в школе на вопрос «что больше 2 или 3» ученик ответит «я нашел звездочку».

ilovewindows ★★★★★ ()
Ответ на: комментарий от anonymous

У Dron'а код намного симпатичнее получился, да и написал он его, надо думать, побыстрее ТС. Всё дело навыка. Начав в яслях, к пенсии можно уверенно решать задачи из ОП на Си.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Aswed

Но лучше для разности указателей использовать ptrdiff_t.

anonymous ()
Ответ на: комментарий от vodz

А вот и тамплиеры подоспели. Защищать свою единственную правильную веру.

Aswed ★★★★★ ()
Ответ на: комментарий от Deleted

На сколько я знаю адрес+1 уже прибавит разрядность, соответствующую типу указателя.

Rupricht ★★ ()

Регулярками-то проще будет. И даже надёжнее — не надо закладываться в алгоритме на то, что искомая подстрока оканчивается там, где появляется '<'.

#include <glib.h>

int main(void) {
  const char *data[] = {
      "<tr> <th>Test_Value_1</th> <th>4334</th> </tr>",  //
      "<tr> <th>Test_Value_2</th> <th>5467</th> </tr>",  //
      "<tr> <th>Test_Value_3</th> <th>34543</th> </tr>", //
  };

  const char *tpl = "<tr> <th>(.*?)</th> <th>(.*?)</th> </tr>";

  GRegex *regex = g_regex_new(tpl, 0, 0, NULL);
  int capture_count = g_regex_get_capture_count(regex);

  for (int k = 0; k < 3; k++) {
    GString *s = g_string_new(NULL);
    GMatchInfo *match_info;

    g_regex_match(regex, data[k], 0, &match_info);
    if (g_match_info_matches(match_info)) {
      for (int capture_idx = 1; capture_idx <= capture_count; capture_idx++) {
        gchar *word = g_match_info_fetch(match_info, capture_idx);
        g_string_append(s, word);
        g_string_append(s, ",");
        g_free(word);
      }
    }

    g_match_info_free(match_info);

    gchar *res = g_string_free(s, FALSE);
    g_print("%s\n", res);
    g_free(res);
  }

  g_regex_unref(regex);
  return 0;
}

Для скорости можно заморочиться минимизацией копирования. Например, брать результаты с помощью g_match_info_fetch_pos().

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

зачем ты человеку велосипед поломал? он на нём ещё даже толком не поездил...

vasyan ()
Ответ на: комментарий от RazrFalcon

Судя по названиям тегов, это HTML. Лучше тогда уж HTML-парсер брать.

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

Лучше тогда уж HTML-парсер брать

Переписать код на расте и прикрутить к нему серво :D

redgremlin ★★★★★ ()
Ответ на: комментарий от i-rinat

Нормальный парсер HTML даже мелкомягкие написать хорошо не могут :)

Для исходного примера можно вообще написать тривиальщину, которая удаляет всё что в <XXX>.

vodz ★★★★★ ()
Ответ на: комментарий от i-rinat

Это недостаточно глобально и надёжно. А раст хотя бы не даст совершить такую же ошибку, как у ТС.

redgremlin ★★★★★ ()

xpath уже предлагали?

P.S. рекаптча должна умереть

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.