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 - явно взято откуда-то из файла, но как оно могло пробраться в переменную, и не засветиться в выводе этой переменной ? ЧЯДНТ ?

★★★★★

Ответ на: комментарий от wandrien

И? Что мешает существовать файловому пути со знаками процента в нём?

Ты перепутал адресата с этим вопросом.

Я переименовал темы вставив эти самые %d и прочая - все работает норм. Если директория существует и доступна - она обрабатывается.

Поставь уже свой ник себе на комп, хватит себя мучать.

Ты просто перешел на личности, не в силах аргументировать необходимость черезжопной работы со строками в С.

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

Ты перепутал адресата с этим вопросом.

Нет, не перепутал. Ты не понимаешь, что такое printf(), и о чем тебе вообще говорили относительно него.

Ты просто перешел на личности, не в силах аргументировать необходимость черезжопной работы со строками в С.

Не, я реально не вдупляю, зачем ты себя мучаешь. В питоне работа с гтк - говно. Си ты не осиливаешь. Да и сам гтк, если уж по чесноку, то еще говно. В итоге ты долбиштся в какую-то по***ту без всякого фана.

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

аргументировать необходимость черезжопной работы со строками в С.

Зачем мне «аргументировать необходимость», если она просто есть? Надеюсь, от меня не требуется «аргументировать необходимость» того, что Солнце встаёт на востоке, а медь проводит ток?

Это просто объективный факт, как что-то устроено. Тебе рассказывают, как с этим работать, дают конкретные указания. Ты изводишься на говно и вопишь «Почему сталь не мягкая?? Я вас спрашиваю, почему сталь не мягкая как поролон??? Я пробовал резать сталь ножницами для ткани, она не режется!!! Зачем ви аргументируете черезжопную работу болгаркой????»

Чел, ну ты можешь пойти в портные, тут свобода выбора как бы.

wandrien ★★
()

В Си же нет типа-строки. Поэтому и конкатенировать нечего. Максимум там есть строковые литералы, которые, по факту, являются просто набором целочисленных элементов типа char. Кстати, литералы складываются прекрасно:

puts("Hello," " world");

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

Если человек понимает принцип работы ЦПУ, то он должен и понимать, что невозможно написать реализацию сложения строк без манипуляций с байтами. То, что в других языках можно складывать строки с помощью оператора конкатенации - это заслуга разработчиков этого языка, которые проделали всю низкоуровневую рутину за пользователя. Часто такие языки имеют ограничения по возможностям доступа к памяти, по скорости работы, по доступным платформам, могут иметь непреодолимые зависимости от интерпретатора или виртуальной машины. Такова цена за удобства.

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

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

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

Мне вот интересно (весь тред не читал): а хоть кто-нибудь намекнул ТС что его split() (a) течёт не по-детски, (b) жутко неэффективен, (c) нахрен не нужен в этой задаче?

bugfixer ★★★★★
()

STC в помощь.

Но нет, просто не будет.

Можно использовать генераторы парсеров. Предпочитаю owl. Есть такой пример:

#using owl.v3

# The strings here are just examples; the real tokenizing code is in main.c.
.token hex-color '#fff' '#CC9966'

color = hex-color | 'rgb' '(' number@r ',' number@g ',' number@b ')'

$ stat parser.h

Size: 59268

$ hex-color '#deface'
r = 222
g = 250
b = 206
$ hex-color 'rgb(1, 2, 3)'
r = 1
g = 2
b = 3
dataman ★★★★★
()
Ответ на: комментарий от windows10

следуют принимать во внимание:

Ken Thompson interviewed by Brian Kernighan at VCF East 2019 https://youtu.be/EY6q5dv_B-o

при подготовке Керниганом : UNIX: A History and a Memoir

в интерью Томсон расказал что Си вырос в процессе реализации интерпретирующего компилятора для бутстрапинга Фортрана на pdp11

так что ...

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

дебилизм с указателями вместо копирования при присваивании

При присваивании копируется то что ты присваиваешь - то есть указатель. Объекта «строка» на этапе выполнения в Си нет, присваивать нечего. Есть во время компиляции только.

Скриптовики

Скрипт это код, где главное внимание уделяется человекопонятным объёктам. Не-скрипт - это код, где главное внимание уделяется работе процессора. Си - однозначно второе. Возможно, он тебе не подходит, но это не повод на него гнать. Разумнее всего считать его синтаксическим сахаром для ассемблера и подсказок оптимизатору (без подсказок ассемблер автоматически оптимизировать затруднительно).

firkax ★★★★★
()
Ответ на: комментарий от windows10
string str = "Hello " + userName + ". Today is " + dateString + ".";

Полное говно как с точки зрения локализации, так и с точки зрения потенциальных уязвимостей в различных контекстах. Лучше писать:

string.Format("Hello {0}. Today is {1}.", userName, dateString);

В контексте HTML или SQL вместо Format была бы какая-нибудь специфическая функция, экранирующая спецсимволы соответствующих языков. Это залог безопасности от инъекций.

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

Это справедливо для всех языков программирования, в том числе и для C, и для C#, и для PHP. Если хотите писать поддерживаемые приложения — пишите правильно и забудьте про конкатенацию.

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

Начинал он вообще с того, что хотел писать под gtk на php

Собственно к этому и вернулся. Код пишется легко и непринужденно. Работает быстрее питона. Встроенные строко-средства мощные. Переменные выглядят так, как должны выглядеть переменные. Типизация не строгая. Рисовалка (gd) отменная. Короче сплошные достоинства.

Хотя конечно системные вещи я все же буду стараться писать на С, он неплохо заставляет шевелить мозгом. Ну ГУЙню к консольным утилитам и системным настройкам лучше писать на том языке, который позволяет думать над тем ЧТО создать, а не тем КАК это создать.

Еще раз спасибо за подсказки =)

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

ЧЯДНТ ?

Язык Си – как и Vim, как и опаска (опасная бритва со сменными лезвиями) – всего лишь острозаточенный узкоспециальный инструмент, требующий достаточно прямых и не трясущихся верхних лап для его использования. Для всех прочих попытки использования любого из 3х упомянутых Магических Артефактов гарантированно приводит к «смерти от 1000 мелких порезов».

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