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)
Ответ на: комментарий от windows10

Я уже думаю что printf просто калеченный, как и все в С

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

char *ret = malloc(sizeof(char) * (ptr - s + 1));
memcpy(ret, s, (ptr - s + 1));
return ret;
anonymous
()
Ответ на: комментарий от anonymous

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

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

вывел бы последнее присвоенное значение

Чему равно последнее присвоенное значение? (с учётом типа переменной)

anonymous
()

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

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

то оно не переносит полноценно значение в VAR1

Нет, не переносит.

Тебе надо поиграться с указателями просто на досуге.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от 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)
Ответ на: комментарий от anonymous

Надеюсь ты выделяешь в своём новом варианте память под строку?

Да. По размеру элемента массива +1. И даже освобождаю после, да =)

windows10 ★★★★★
() автор топика
Ответ на: комментарий от 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
()

Ловлю вайбы зашкаливающего тупняка, прямо как в старых тредах @anonimous про круг :3

hateyoufeel ★★★★★
()

printf(gtk_path)

printf(fg_color)

В фукции printf первый аргумент это формат, печатаемые значения начинаются со вторго аргумента.

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

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

firkax ★★★★★
()

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

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

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

Код должен быть максимально кроссплатформенным. Никакие расширения компилятора или системно-специфичные функции использоваться не должны.

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

Код должен быть максимально кроссплатформенным

Кому должен?

alex1101
()
Ответ на: комментарий от LongLiveUbuntu

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

wandrien ★★★
()

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

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

    #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 ★★★
()
Ответ на: комментарий от wandrien

Вообще, glib – сраное говнище, а не либа. Есть более пригодные сишные либы, но я бы плюнул и взял плюсы (или руст).

hateyoufeel ★★★★★
()
Ответ на: комментарий от 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)
Ответ на: комментарий от anonymous

В фукции printf первый аргумент это формат, печатаемые значения начинаются со вторго аргумента.

То есть вместо printf(«Hello, world!») предлагаете printf(«%s», «Hello, world!») ?

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

Зависит от того, откуда берётся печатаемая строка.

Про пример из кода ТСа анон всё правильно сказал.

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

Просто вы тут все лалки анскильные, не можете осилить сишку.

Кто то вон про руст кукарекает, кто то про плюсы. А сами и двух строк наптсать не могут.

anonymous
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.