LINUX.ORG.RU

Подскажите С-нубасу как банально распарсить строку в массив.

 ,


1

6

Приветствую. Казалось бы, тривиальная в 2023 году вещь - распарсить строку по делимитеру и загнать это в массив. Но нет, просто не будет.

Впрочем вопрос не в этом. Есть код. Описания переменных и прочая, я опущу, перейду сразу к сути.

Алгоритм ну вроде как прост, работает и на питоне, и на пыхе, а вот на С делает какую-то срань, хотя скорее всего я банально не до конца понимаю нюансов С, в связи с чем и прошу помощи.

printf("\n============ Parsing: ");printf(gtk_path);printf(" ========\n");
fg_color = "#888888";
bg_color = "#AAAAAA";

filePointer = fopen(gtk_path, "r");

while(fgets(buffer, bufferLength, filePointer)) {

 if (strstr(buffer, " fg_color ") != NULL)  {
  printf("\nFound fg_color entry: ");
  char **arr = split(buffer, ' ');
  fg_color = trim(arr[2]);
  printf(fg_color); // <<<<
 }

 if (strstr(buffer, " bg_color ") != NULL)  {
  printf("\nFound bg_color entry: ");
  char **arr = split(buffer, ' ');
  bg_color = trim(arr[2]);
  printf(bg_color); // <<<<
 }

}

fclose(filePointer);
printf("\n *** \n");printf("Main color: ");printf(fg_color);printf("BG color: ");printf(bg_color);printf("\n");


// Для информации приведу функции split и trim, хотя дело вряд ли в них.

char **split(char *str, char delim) {
  char **arr = malloc(sizeof(char *) * (strlen(str) + 1));
  int i = 0;
  for (char *p = strtok(str, &delim); p; p = strtok(NULL, &delim)) {
    arr[i++] = p;
  }
  return arr;
}

char *trim(char *s) {
    char *ptr;
    if (!s)
        return NULL;   // handle NULL string
    if (!*s)
        return s;      // handle empty string
    for (ptr = s + strlen(s) - 1; (ptr >= s) && isspace(*ptr); --ptr);
    ptr[1] = '\0';
    return s;
}

Задача блока - прочитать CSS-файл, и выдрать с него полторы строчки в массив.

Сначала присваиваем двум переменным какое-то значение, например #888888 и #AAAAAA;

Читаем построчно файл, ищем в каждой строке нахождение подстроки, если подстрока найдена, тогда парсим ее в массив, и присваиваем нашей главной переменной значение массива с определенным индексом, и ГЛАВНОЕ - тут же выводим эту переменную на экран.

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

А вот что оно выводит:

============ Parsing: /usr/share/themes/Relax-Light-GTK/gtk-3.0/gtk.css ========

 *** 
Main color: #888888BG color: #AAAAAA

============ Parsing: /usr/share/themes/White - OE2-GTK/gtk-3.0/gtk.css ========

Found fg_color entry: #5C616C;
Found bg_color entry: #FAFAFA;
 *** 
Main color:  #000000;
BG color:  #000000;


Вопрос: откуда нах взялся этот #000000 ?

Когда подстрока не встречается в строке (т.е. файл не содержит ни fg_color ни bg_color) - возвращаются правильные значения того что я установил. Этот кусок работает правильно.

Да, возможно парсер работает криво, но ведь каждое присваивание fg_color = сопровождается printf'ом, и в пределах if'а с парсером видно, что парсер отрабатывает на отлично. #000000 - явно взято откуда-то из файла, но как оно могло пробраться в переменную, и не засветиться в выводе этой переменной ? ЧЯДНТ ?

★★★★★

Проблема в том, что тут строки не копируются нигде. Вот программа обработала одну строку, записала что-то в fg_color, а уже при следующем вызове fgets всё перезапишется и строка по адресу fg_color испортится

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

Вообще по идее нет, только если подстрока " fg_color " встретится в файле еще раз.

Но так или иначе, после каждого присваивания значения переменной, стоит printf, он же должен что-то вывести.

Я уже думаю что printf просто калеченный, как и все в С, и на самом деле fg_color может оказаться «#242526\n#000000», а printf вывел только кусок.

windows10 ★★★★★
() автор топика
Последнее исправление: windows10 (всего исправлений: 1)
Ответ на: комментарий от windows10

строка у тебя перезаписывается в fgets а не если подстрока встретится, потому оно дальше и не работает. Толк то от указывающих на куски новой строки указателей?

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

Все равно не могу въехать.

1. Есть цикл, перебирающий текст построчно;

2. В цикле есть условие: если STR содержит SUBSTR, то присвоить VAR=SUBSTR и вывести printf (VAR);

3. После окончания цикла еще раз вывести printf (VAR).

Как VAR может иметь разные значения?

Я понимаю в тексте SUBSTR может встречаться несколько раз. Но тогда бы printf (VAR) отработал несколько раз, а результирующий printf (VAR) вывел бы последнее присвоенное значение. Или не ?

windows10 ★★★★★
() автор топика
Последнее исправление: windows10 (всего исправлений: 1)

По поводу перезатираний уже сказали, поэтому просто сделаю по другому =)

dron@gnu:~$ gresource extract ./gtk.gresource /org/gnome/arc-theme/gtk-main-dark.css > ~/gtk.css
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>

#define check(x,p) for(;!(x);puts(p),assert(x));

int main(int argc, char *argv[])
{
    FILE * css_file = fopen(argv[argc-1],"r");
    check(css_file,"Ошибка открытия файла");
    char fg_color[0x10] = {"color_not_found"}; bool has_fg = false;
    char bg_color[0x10] = {"color_not_found"}; bool has_bg = false;
    char cur_line[0xFF] = {0};
    while(fgets(cur_line,sizeof(cur_line),css_file))
    {
        if(!has_fg)
        {
           has_fg = (sscanf(cur_line,"@define-color fg_color #%15s;",fg_color) == 1);
        }
        if(!has_bg)
        {
           has_bg = (sscanf(cur_line,"@define-color bg_color #%15s;",bg_color) == 1);
        }
    }
    (has_fg) ? fg_color[strlen(fg_color)-1] = '\0' : 0;
    (has_bg) ? bg_color[strlen(bg_color)-1] = '\0' : 0;

    printf("fg:%s | bg:%s \n",fg_color,bg_color);
    return 0;
}
dron@gnu:~$ gcc test.c
dron@gnu:~$ ./a.out gtk.css
fg:D3DAE3 | bg:383C4A 
dron@gnu:~$ 
LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

Огромное спасибо, хотя мне нужен не столько код, сколько понять что к чему.

Я так понимаю когда я делаю что-то типа char *VAR1 = ARR[2], то оно не переносит полноценно значение в VAR1, а просто указывает на область ARR[3] ?

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

Замени return s; в функции trim() на

Кстати работает не совсем корректно. В некоторых строках возвращает спецсимволы.

============ Parsing: /usr/share/themes/Mojave-light-solid/gtk-3.0/gtk.css ========

Found fg_color entry: #242424;���~0

Found bg_color entry: #f5f5f5;���~0

В моем варианте работает норм, но все равно спасибо.

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

Я уже думаю что printf просто калеченный, как и все в С, и на самом деле fg_color может оказаться «#242526\n#000000», а printf вывел только кусок.

printf может вывести «кусок переменной» только в двух случаях: либо если перемудрить со спецификациями форматирования, либо если внутри строки есть нулевой байт \0 — тогда всё после него будет «потеряно». Так что на printf при отладке можно положиться. С другой стороны, отладчики тоже никто не отменял :)

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

Надеюсь ты выделяешь в своём новом варианте память под строку? fg_color у тебя является лишь указателем на строку. Изначально этот указатель указывает на статическую строку из литерала, которая компилятором помещается, обычно, в ридонли-секцию. И если ты не выделяешь память под новую строку хотя бы на стеке, то сегфолта, при копировании туда другой строки, не избежать.

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

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

а посмотреть на вот этих, которые сразу Ъ код начинают херачить - так у них вообще НОЛЬ понимания что они делают и зачем. И ессно никакие программы по паскалю они уже проходить не желают - они же тру хацкеры уже, это уже не для них.

А потом они идут работать куда-то и там пишут вот все это говно, от которого, когда приходишь на поддержку, удавиться хочется.

Зато Ъ. И типа, используются языки для Настоящих Программистов, не то что сраный паскаль

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

Ну пукнул, и дальше чо ?

Ты вот прямо сейчас мне хочешь сказать, что на паскале вытягивание подстроки из файла в переменную выглядело бы по-другому ? Не while not eof? Не readln в string ? Удиви, о гуру паскаля. Хочу тебе напомнить, если ты гулял информатику в универе, что в паскале string - это string, char это char, а pointer это pointer. Присваивание := подразумевает собой копирование области памяти одной переменной в область памяти другой, как в принципе и в любом ЯП.

В С для этого существует отдельная функция. Неудобно, но уж как есть.

Язык для Настоящих Программистов я использую по необходимости, поскольку юзаю ГТК, а биндинги, и тем более ООП-дроч мне не подходит.

Жду алгоритм выдергивания подстроки из файла в переменную на пацкале, гуру.

windows10 ★★★★★
() автор топика
Последнее исправление: windows10 (всего исправлений: 1)
Ответ на: комментарий от lovesan

у них вообще НОЛЬ понимания что они делают и зачем.

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

У тебя понимание есть, а ты за ними подтираешь. Не наводит на размышление?

rupert ★★★★★
()

g_strsplit() тебе нужна.

Вообще открой /usr/share/gtk-doc/html/glib/index.html на локалхосте, много полезного найдёшь. Не знаю, в каком он у тебя пакете должен быть. Если гента, то наверное как часть glib2 ставится при соответствующем флаге на документацию.

wandrien ★★
()
Ответ на: комментарий от LINUX-ORG-RU
  char fg_color[0x10] = {"color_not_found"}; bool has_fg = false;
  char bg_color[0x10] = {"color_not_found"}; bool has_bg = false;

Вот именно из-за таких идиотов, пишущих write-only code, у C соответствующая репутация. Я, наверно, пару минут не мог найти определение has_fg, потому что ты сэкономил аж ДВЕ строки.

anonymous
()

Си это не про сплит строк. Это про то, как написать код так, чтобы он делал то, для чего тебе там нужен был сплит на один проход строки + 20 операций, без дополнительного выделения памяти и чтобы всё это работало даже на микроконтроллере без стандартной библиотеки.

Короче, бери пистончик и не выделывайся.

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

не нужны тут никакие маллоки-шмаллоки

определи там у себя максимально возможный размер строки с определением цвета, например как

    #define SZ_COLOR  8 // включая завершающий 0
    char fg_color [SZ_COLOR] = "#888888";
    char bg_color [SZ_COLOR] = "#AAAAAA";

поправь там у себя, вместоfg_color = trim(arr[2]); напиши strncpy(fg_color, trim(arr[2]), SZ_COLOR - 1);

bg_color поправь соответственно

и все заработает

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

Не влезет в буфер и будет пропущен. Но ЕМНИП @define-color это GTKшное расширение CSS в виде препроцессора, если оно будет где то в середине строки стиля то CSS сломается. Дефайн должен быть записан на отдельной строчке.

А если это не так то надо грузить пару строк или весь файл и strstr находить ключ только потом сравнивать имя и только потом чситать значение до первого ; или пробел

LINUX-ORG-RU ★★★★★
()

CSS сплитами не распарсить. Но если сильно нужно, то попробуй питунию:

❯ python
Python 3.11.5 (main, Sep  2 2023, 14:16:33) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> contents=open('/var/lib/flatpak/runtime/org.gtk.Gtk3theme.Breeze/x86_64/3.22/0f27bc64b3ca031e9804a737d532d7015cda05fa8198409bcb70aac2dc9fe5a2/files/gtk.css').read()
>>> import re
>>> DEFINE_COLOR_RE=re.compile(r'@define-color (\S+) (\S+);$', re.MULTILINE)
>>> DEFINE_COLOR_RE.findall(contents)
[('theme_fg_color_breeze', '#232629'), ('theme_text_color_breeze', '#232629'), ('theme_bg_color_breeze', '#eff0f1'), ('theme_base_color_breeze', 'white'), ('theme_view_hover_decoration_color_breeze', '#3daee9'), ('theme_hovering_selected_bg_color_breeze', '#3daee9'), ('theme_selected_bg_color_breeze', '#3daee9'), ('theme_selected_fg_color_breeze', 'white'), ('theme_view_active_decoration_color_breeze', '#3daee9'), ('insensitive_bg_color_breeze', '#d8dadd'), ('insensitive_base_fg_color_breeze', '#e8e8e8'), ('insensitive_selected_fg_color_breeze', '#e8e8e8'), ('theme_unfocused_fg_color_breeze', '#232629'), ('theme_unfocused_text_color_breeze', '#232629'), ('theme_unfocused_bg_color_breeze', '#eff0f1'), ('theme_unfocused_base_color_breeze', 'white'), ('theme_unfocused_selected_bg_color_alt_breeze', '#3daee9'), ('theme_unfocused_selected_fg_color_breeze', 'white'), ('insensitive_unfocused_bg_color_breeze', '#d8dadd'), ('insensitive_unfocused_selected_fg_color_breeze', '#e8e8e8'), ('theme_unfocused_view_bg_color_breeze', '#e8e8e8'), ('borders_breeze', '#bcbebf'), ('unfocused_borders_breeze', '#bcbebf'), ('theme_button_background_normal_breeze', '#fcfcfc'), ('theme_button_foreground_normal_breeze', '#232629'), ('theme_button_foreground_active_breeze', 'white'), ('theme_button_foreground_active_insensitive_breeze', '#e8e8e8'), ('theme_button_foreground_active_backdrop_breeze', 'white'), ('theme_button_foreground_active_backdrop_insensitive_breeze', '#e8e8e8'), ('warning_color_breeze', '#f67400'), ('success_color_breeze', '#27ae60'), ('warning_color_backdrop_breeze', '#f67400'), ('success_color_backdrop_breeze', '#27ae60'), ('link_color_breeze', '#2980b9'), ('link_visited_color_breeze', '#9b59b6'), ('theme_titlebar_foreground_backdrop_breeze', '#707d8a'), ('theme_titlebar_background_backdrop_breeze', '#eff0f1'), ('tooltip_text_breeze', '#232629'), ('tooltip_background_breeze', '#f7f7f7'), ('tooltip_border_breeze', '#c2c3c4'), ('content_view_bg_breeze', 'white'), ('theme_fg_color', '@theme_fg_color_breeze'), ('theme_text_color', '@theme_text_color_breeze'), ('theme_bg_color', '@theme_bg_color_breeze'), ('theme_base_color', '@theme_base_color_breeze'), ('theme_selected_bg_color', '@theme_selected_bg_color_breeze'), ('theme_selected_fg_color', '@theme_selected_fg_color_breeze'), ('insensitive_bg_color', '@insensitive_bg_color_breeze'), ('insensitive_fg_color', '@insensitive_fg_color_breeze'), ('insensitive_base_color', '@insensitive_base_color_breeze'), ('theme_unfocused_fg_color', '@theme_unfocused_fg_color_breeze'), ('theme_unfocused_text_color', '@theme_unfocused_text_color_breeze'), ('theme_unfocused_bg_color', '@theme_unfocused_bg_color_breeze'), ('theme_unfocused_base_color', '@theme_unfocused_base_color_breeze'), ('theme_unfocused_selected_bg_color', '@theme_unfocused_selected_bg_color_breeze'), ('theme_unfocused_selected_fg_color', '@theme_unfocused_selected_fg_color_breeze'), ('unfocused_insensitive_color', '@unfocused_insensitive_color_breeze'), ('borders', '@borders_breeze'), ('unfocused_borders', '@unfocused_borders_breeze'), ('warning_color', '@warning_color_breeze'), ('error_color', '@error_color_breeze'), ('success_color', '@success_color_breeze'), ('content_view_bg', '@content_view_bg_breeze')]
rtxtxtrx ★★
()
Ответ на: комментарий от windows10

Да поэтому написание парсера - это нетривиальное занятие и нужно посимвольно все читать и далее классифицировать токены. Потому как они все валидны (не знаю что за подмножество CSS используется):

$var: #deadbeef;
$var : 
#deadbeef
;
$var/**/:#deadbeef;

Но тут можно обойтись регакспами

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

мущщина, у вас ус отклеился

Задача блока - прочитать CSS-файл

примерчики валидного rgb синтаксиса тебе привести?

rgb(255,0,153)
rgb(255, 0, 153)
rgb(255, 0, 153.0)
rgb(100%,0%,60%)
rgb(100%, 0%, 60%)
rgb(255 0 153)

поэтому если ты ожидаешь что в твоем CSS будет задан цвет в формате RGB это означает, что твой парсер типа split(buffer, ' '); вообще мимо кассы.

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