Adott egy konfig file, pl.
var1=value1
var2=value2
...
amit az alabbi struct-ba kellene beletenni:
struct __config cfg {
int var1,
int var2,
char var3[100],
char var4[100],
...
};
Hogyan oldanad meg? Olyasmire gondoltam, hogy egy while ciklusban beolvasom a konfig file-t, es szetszedem a sorokat key-value parokra, ez ok, de hogy lehet elerni a cfg->var1-et, ill. a cfg->var2-t?
Ilyesmire gondoltam (pszeudokoddal):
while((key, val) = read(line)){
if(line == int_valtozo) parser_int_var(cfg->key, val);
if(line == char_valtozo) parse_char_var(cfg->key, val);
}
Azt, hogy melyik valtozo int, ill. char, azt tetszes szerinti modon lehet nyilvantartani, pl. tombben stb.
- 2138 megtekintés
Hozzászólások
Léteznek kész eszközök az ilyen jellegű feladatokra: lex és yacc (GNU alapokon flex és bison).
http://directory.fsf.org/project/bison/
http://directory.fsf.org/project/flex/
Ezek a programok lehetőséget biztosítanak pl. programozási nyelvi felismerők írására, kimenetük C forráskód.
G.
============================================
"Share what you know. Learn what you don't."
- A hozzászóláshoz be kell jelentkezni
ezek kicsit tullonek egy konfigfile parsolason, nem gondolod?:)
mindjart tanitsuk meg LR parsert irni!
- A hozzászóláshoz be kell jelentkezni
A bison (ami asszem' tartalmaz lexikális elemzőt is, de ez nem biztos) LALR(1)-es elemző :)
Egyébként meg hogy túllő-e, azt neki kell látnia: pl. akar-e bal oldalon szereplő szimbólumot később a jobb oldalon látni, jobb oldalon több szimbólumot... :)
szerk.: de ha csak azt megnézed, h van int_valtozo meg char_valtozo, tehát szét kell szedni típusonként, amihez minimum regexp kell, szerintem csak jól jár vele.
- A hozzászóláshoz be kell jelentkezni
Én bizony BISON -nal csinálnám :)
Nagyban elősegiti a jövőbeli bővithetőséget.
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
En szepen felparsolnam, eltennem egy lancolt listaba a kulcs - ertek parokat, szovegkent.
Aztan irnek plyan fuggvenyeket, pl. hogy int GetIntValue(key,default). Ez kikeresi a listabol a key nek megfelelo part, aztan az ereteket int-te alakitja, es visszaadja. Ha nem tudja, vagy nincs ilyen key, akkor a default -ot adja vissza.
Ugyanigy megirnam a GetBoolValue(key, default), a GetCharValue(key,default), char* GetStringValue(key,default), stb.stb. fuggvenyeket.
Meg kell majd egy fuggveny, ami felszabaditja a listat.
Minezt meg lehet ugy csinalni, hogy definialsz mondjuk egy ilyemi struct -ot:
struct {
char *key,*value;
} _config_item;
struct {
_config_item *item,*next,*prev;
} _config_list_item;
struct {
char filename[255];
File* file;
_config_list_item * first_item,*last_item;
} ConfigFile;
Aztan kell egy olyan fuggveny, ami felparsolja a konfig-fajlt, legyen mondjuk:
ConfigFile* LoadConfigFile(char* filename);
Ha nem sikerult, null -t ad vissza, ha sikerult.
Aztan kell ami vegig megy a listan, es mindent felszabadit:
void DoneConfig(configFile *)
Es a fuggvenyek, amik kiszedik kulcs alapjan az ertekeket, meg mondjuk igy neznenek ki:
int GetIntValue(ConfigFile*, char* key, int default);
Igy univerzalis kodot keszitenel, annyi config fajlt tudnal egy idoben hasznalni, amennyit akarnal.
Bar biztos van kesz kod erre, de gyakorlakent erdemes megirni, nem nagy ordongosseg.
- A hozzászóláshoz be kell jelentkezni
libconfig?
--
Fontos feladatot soha ne bizz olyan gepre, amit egyedul is fel tudsz emelni!
- A hozzászóláshoz be kell jelentkezni
Én végül írtam egyet magamnak az .ini fájlok mintájára, két rutin hívás a végeredmény:
int FetchCfg(char *FileName,char *Section,char *Entry,char *Frm,...);
int PatchCfg(char *FileName,char *Section,char *Entry,char *Frm,...);
a vfprintf és a vsscanf az alapja a varargs cuccok között nézd.
* Én egy indián vagyok. Minden indián hazudik.
- A hozzászóláshoz be kell jelentkezni
libxml2 parser?
- A hozzászóláshoz be kell jelentkezni
koszonom mindenki hozzaszolasat, meg gondolkodom a dolgon...
SPAMtelenül - MX spamszűrő szolgáltatás, ahogyan még sosem próbálta
- A hozzászóláshoz be kell jelentkezni
Bár C++ és nem C, de remek megoldás: http://code.jellycan.com/simpleini/
- A hozzászóláshoz be kell jelentkezni
Uram eg... ez elso korben strtok masodik korben regex, ennel bonyolultabb egy ilyennek nem kell. A regex meg jo is, mert ha mar ugyis kitanultad a regexet, lehet parsolaskor rogton validalni is a beolvasott erteket.
Mondjuk en egy nev-ertek strukt-ot hasznalnek vagy tombben vagy lancolt listaban.
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
struct __config {
int var1;
int var2;
char var3[100];
char var4[100];
} cfg;
int string_parser(char * src, char *target, int limit)
{
strncpy(target,src,limit);
target[limit]='\0';
return 0;
};
int int_parser(char * src, int * target, int limit)
{
*target=strtol(src, (char **) NULL, 10);
return 0;
};
struct _parse_rule
{
char * name;
int(*parser)(char*,void*,int);
size_t offset;
int limit;
};
struct _parse_rule config_parse_rules[]=
{
{"var1",int_parser,offsetof(struct __config,var1),sizeof(cfg.var1)},
{"var2",int_parser,offsetof(struct __config,var2),sizeof(cfg.var2)},
{"var3",string_parser,offsetof(struct __config,var3),sizeof(cfg.var3)},
{"var4",string_parser,offsetof(struct __config,var4),sizeof(cfg.var4)},
{NULL,NULL,0,0}
};
int parse(FILE* file, struct __config *target_cfg, struct _parse_rule *rules)
{
char *line = NULL;
size_t size=0;
while (0<getline(&line,&size,file))
{
char *chpos=strchr(line,'=');
if (chpos)
{
*chpos='\0';
int i=0;
while ( rules[i].name)
{
if (!strcmp(line,rules[i].name))
{
if (rules[i].parser(chpos+1,(char*)target_cfg+rules[i].offset,rules[i].limit))
{
printf("Failed to parse %s : \"%s\"",line,chpos+1);
}
break;
}
i++;
}
if (!rules[i].name)
{
printf("Unknown key \"%s\" \n",line);
}
}
}
if (line) free(line);
}
int main()
{
FILE * file;
file=fopen("test.file","r");
parse(file,&cfg,config_parse_rules);
printf("var1: %d \n",cfg.var1);
printf("var2: %d \n",cfg.var2);
printf("var3: %s \n",cfg.var3);
printf("var4: %s \n",cfg.var4);
}
</code>
Valami ilyesmi jutott eszembe, nemi makrozassal el lehet erni, hogy uj kulcs, vagy tipus hozzadasa csak par sor plusz legyen.
Amit nem lehet megirni assemblyben, azt nem lehet megirni.
- A hozzászóláshoz be kell jelentkezni
ennél egy picit hosszab univrzálisra megírni, olyan módod, ahogy fentebb írtam.
- A hozzászóláshoz be kell jelentkezni
Persze. De a kerdezo egy strukturat akkar kitolteni C-ben viszonylag egyszeruen, velhetoleg egyszer indulaskor.
Java/C++ Qt vilagban teljesen megszokott amit irtal.
A getter sereged, csomo olyan ertek megadasara kenyszerit a getterek hivasakor, amit struktura kezdo erteknek is meg lehetne adni forditas idoben is akkar.
A perser amit javasolsz stringkent tarolna mindent, es lekerdezeskor konvertalna mindig. (Tobblet koddal, memoriaval esetleg proxizva is megoldhato)
(perl -ben, meg vegtelen egyszeru lenne a dolog :) )
Amit meg erdemes megjegyzni kodrol, hogy O(n*m) -en stringet hasonlit ahol m~n. 1000 kulcsnal mar erdemes, int -eknek megfeltetni, vagy fat hasznalni, vagy hash-eket.
Amit nem lehet megirni assemblyben, azt nem lehet megirni.
- A hozzászóláshoz be kell jelentkezni
while (0<getline(&line,&size,file))
{
char *chpos=strchr(line,'=');
if (chpos)
{
*chpos='\0';
int i=0;
while ( rules[i].name)
{
if (!strcmp(line,rules[i].name))
{
if (rules[i].parser(chpos+1,(char*)target_cfg+rules[i].offset,rules[i].limit))
{
printf("Failed to parse %s : \"%s\"",line,chpos+1);
}
break;
}
i++;
}
if (!rules[i].name)
{
printf("Unknown key \"%s\" \n",line);
}
}
}
if (line) free(line);
}
int main()
{
FILE * file;
file=fopen("test.file","r");
parse(file,&cfg,config_parse_rules);
printf("var1: %d \n",cfg.var1);
printf("var2: %d \n",cfg.var2);
printf("var3: %s \n",cfg.var3);
printf("var4: %s \n",cfg.var4);
}
Lemaradt a fele
Amit nem lehet megirni assemblyben, azt nem lehet megirni.
- A hozzászóláshoz be kell jelentkezni
Az include-k is hianyosak, de mindegy. Maskor <, tudod... :-)
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Kossz, turul, hajszalpontosan ilyenre gondoltam. Kis modositassal be is epitettem a clapf konfig parse-olasaba. Annyit tuningoltam rajta, hogy meg lehet adni default erteket a strukturaban, ill. kezeli a float + multiline stringeket is.
Az offsetof() fv-t eddig nem ismertem, ill. a 'struct _parse_rule' definicioval is tanultam valamit, bar utobbi nelkul is megoldhato lenne a feladat.
Az egyeb lib-ekkel is biztos elegansan meg lehet oldani a feladatot, de (szamomra) annal jobb, minel kevesebb kulso lib kell hozza.
Megegyszer koszonet mindenkinek, aki megosztotta az otletet/kodjat :-)
SPAMtelenül - MX spamszűrő szolgáltatás, ahogyan még sosem próbálta
- A hozzászóláshoz be kell jelentkezni