/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
Hente ord/tal ud fra tekstmængde?
Fra : Allan Johansen


Dato : 11-02-03 19:35

Hej NG

Jeg har en fil med teksten der ser nogenlunde sådan her ud:

tekasd:9868755 86565 8709707 9765875 875
sdf:34234 9878097 098787 78676 769
kurt:1234 89769876 98779 897879 676
kjlkjlkh:0 07087807 87686 8000 44223

Det jeg gerne vil have ud af dette er ordet "kurt" og tallet "1234" lige
efter (altid adskilt af kolon), således at hver del bliver smidt i hver sin
variablen.

Jeg kan kun komme frem til noget lignende dette:

fp=fopen("/proc/net/dev","r");
while(!feof(fp))
{
c = fgetc(fp);
if(c == ':')
{
/*tag det til venstre og smid ind i variabel navn*/
/*tag det til højre og smid ind i variabel tal*/
}

}
fclose(fp);

printf("%s\n", navn);
printf("%i\n", navn);

Er der nogle der kan hjælpe/se hvad jeg mangler, eller kender et sted på
nettet, hvor jeg kan læse om dette?

På forhånd mange tak!

Mvh. Allan



 
 
soren davidsen (11-02-2003)
Kommentar
Fra : soren davidsen


Dato : 11-02-03 20:08

"Allan Johansen" <AllanJ@post.cybercity.dk> writes:

> Hej NG
>
> Jeg har en fil med teksten der ser nogenlunde sådan her ud:
>
> tekasd:9868755 86565 8709707 9765875 875
> sdf:34234 9878097 098787 78676 769
> kurt:1234 89769876 98779 897879 676
> kjlkjlkh:0 07087807 87686 8000 44223
>
> Det jeg gerne vil have ud af dette er ordet "kurt" og tallet "1234" lige
> efter (altid adskilt af kolon), således at hver del bliver smidt i hver sin
> variablen.
>
> Jeg kan kun komme frem til noget lignende dette:
>
> fp=fopen("/proc/net/dev","r");
> while(!feof(fp))
> {
> c = fgetc(fp);
> if(c == ':')
> {
> /*tag det til venstre og smid ind i variabel navn*/
> /*tag det til højre og smid ind i variabel tal*/
> }
>
> }
> fclose(fp);
>
> printf("%s\n", navn);
> printf("%i\n", navn);
>
> Er der nogle der kan hjælpe/se hvad jeg mangler, eller kender et sted på
> nettet, hvor jeg kan læse om dette?

FILE *f;
char buf[1024], *tmp;
f = fopen("/the/file","r");
while (fgets(buf, 1024, f)) {
   tmp = strchr(buf, ':');

   // ingen ':' i linjen
   if (!tmp)
      continue;

   *(tmp++) = 0;

   // buf indeholder det der staar til venstre, og tmp det h0jre.

   ..
}

tjek man sider for de forsk. funktioner .


mvh,

--

school:soren.davidsenATturtle.math.klte.hu//math-institute/uni-debrecen
other:sorenATtanesha.net//www.tanesha.net

Igor V. Rafienko (11-02-2003)
Kommentar
Fra : Igor V. Rafienko


Dato : 11-02-03 20:14

[ Allan Johansen ]

[ ... ]

> tekasd:9868755 86565 8709707 9765875 875
> sdf:34234 9878097 098787 78676 769
> kurt:1234 89769876 98779 897879 676
> kjlkjlkh:0 07087807 87686 8000 44223
>
> Det jeg gerne vil have ud af dette er ordet "kurt" og tallet "1234"
> lige efter (altid adskilt af kolon), således at hver del bliver
> smidt i hver sin variablen.


Hva avslutter tallet? Whitespace?


> Jeg kan kun komme frem til noget lignende dette:
>
> fp=fopen("/proc/net/dev","r");
> while(!feof(fp))


Denne konstruksjonen tyder oftest på at input'en vil bli lest feil.
Grunnen til dette er at EOF indikator trenger ikke å være satt før
_etter_ at man har lest forbi EOF. Mao., man er nødt til å teste for
hvorvidt inputoperasjonen lyktes likevel, og da blir testen
meningsløs. Som regel mener man:

<consume input item 1>
while ( !feof( ifs ) ) {
<process input item i>
<consume input item i+1>
}


> {
> c = fgetc(fp);
> if(c == ':')
> {
> /*tag det til venstre og smid ind i variabel navn*/
> /*tag det til højre og smid ind i variabel tal*/
> }
>
> }
> fclose(fp);
>
> printf("%s\n", navn);
> printf("%i\n", navn);


Disse printf'ene er litt meningsløse, med tanke på inputstrukturen.

Tja, hva skal man anbefale her?

Variant 1: (egnet for ting som /etc/passwd)
----------

Man definerer en fast grense på hvor stor inputfeltene kan være og man
antar filen er strukturert på linjenivå:

const size_t NAME_LIMIT = 9U;
const size_t KEY_LIMIT = 20U;
const size_t LINE_LIMIT = 1000U;
const char whitespace[] = " \t\v\n";

char name[ NAME_LIMIT ];
char key[ KEY_LIMIT ];
char line[ LINE_LIMIT ];

while ( fgets( line, sizeof line, ifs ) ) {
char *separator = strchr( line, ':' );
size_t name_length = separator - line;
size_t key_length = strcspn( separator, whitespace );

/* error-checking */

memmove( name, line, name_length );
name[ name_length ] = '\0';
memmove( key, separator + 1, key_length );
key[ key_length ] = '\0';

process( name, key );
}

Legg merke til at det mangler feilhåndtering på essensielle steder,
men denne øvelsen er overlatt til leseren.


Variant 2:
----------

Nå tillater vi litt større frihet hva angår størrelsen på navn og
nøkler. Men ting er fortsatt linjeorienterte. Siden man ikke lenger
har et maksimalt antall tegn å jobbe i fra, er vi nødt til å la
datastrukturene våre vokse dynamisk. Det gir heller ikke mening å lese
i "linjer", da vi ikke vet hvor store de er.

Ideen er å simulere en tilstandsmaskin hvor man begynner med å samle
tegn til name fram til man ser ':', og deretter samler vi tegn til key
såfremt det neste tegnet er et siffer:

char *name = allocate();
char *line = allocate();

typedef enum { INNAME, INDIGIT, SKIP } state_t;

int input;
state_t state = INNAME;

while ( (input = fgetc( ifs )) != EOF ) {
if ( input == '\n' ) {
   process( name, key );
reset( name );
   reset( key );
state = INNAME;
}
else if ( input == ':' ) {
/* now we have the name */
process_name( name );
state = INDIGIT;
}
else if ( isalpha( input ) && state == INNAME )
append( name, input );
else if ( isdigit( input ) && state == INDIGIT )
append( key, input );
else {
   /*
    * We have an input character, but it is not part of name or
* key
*/
state = SKIP;
}
}

Man begynner i tilstand "INNAME" -- vi samler opp tegn til navn. Når
vi ser ':', vet vi at navnet er slutt og det skal komme en nøkkel (i
dette tilfellet et tall). Derfor settest tilstanden til INDIGIT. Vi
forblir i den tilstanden inntil vi ser noe annet enn et siffer. Da kan
man sette tilstanden til SKIP og bare lese inn de resterende tegn fra
linjen (det er uinteressant å gjøre noe med de). Når vi så ser '\n',
betyr det at linjen er ferdiglest, de riktige verdiene ligger i name
og line og det er på tide å prosessere de.

Man er nødt til å håndtere vilkårlig lange navn/nøkler, og derfor er
det lurt med hjelpefunksjoner som fikser slikt automatisk. Meningen er
at append() skal ta hånd om det. allocate() lager en string og reset()
"tømmer" den stringen i en passende forstand.


Variant 3: (meget egnet når input'en er litt mer komplisert og/eller
---------- når man er lat)

Vi bruker Lex. Gjerne i kombinasjon med Yacc. Akkurat i dette
tilfellet blir det veldig interessant, fordi du vil gjerne kaste
"resten" av linjen, og det er ikke godt å si hva ligger i den. Jeg går
ut ifra at det går an å fortelle Lex at den skal kaste vekk alt etter
nøkkelen, men da er ISBN 1-565-92000-7 (og evt.
<URL:http://www.opengroup.org/onlinepubs/007904975/utilities/lex.html>
(forresten, er Lex POSIXifisert?)) det riktige stedet å slå opp.


> Er der nogle der kan hjælpe/se hvad jeg mangler, eller kender et
> sted på nettet, hvor jeg kan læse om dette?


I det generelle tilfellet er:

@Book{misc:CPT86,
author = {{Aho, Alfred V.} and {Sethi, Ravi} and {Ullman, Jeffrey D.}},
title = {Compilers - Prin\-ci\-ples, Techniques, and Tools},
publisher = AW,
address = {Reading, MA, USA},
pages = {x + 796},
year = {1986},
ISBN = {0-201-10088-6},
LCCN = {QA76.76.C65 A371 1986}
}

.... å anbefale. I tilfellet ditt er det også lurt å ta en titt på ISBN
0-131-10362-8 (evt. <URL:http://www.accu.org/>).





ivr
PS: Koden er ikke blitt kompilert eller testet
--
<peder> igorr: tcl ja... det er fra de dypeste avgrunnene i helvete det...
<peder> php er bare fra foajeen
            -- pederst på irc

Søg
Reklame
Statistik
Spørgsmål : 177500
Tips : 31968
Nyheder : 719565
Indlæg : 6408518
Brugere : 218887

Månedens bedste
Årets bedste
Sidste års bedste