Christian_ Skrevet 20. mars 2012 Del Skrevet 20. mars 2012 Hei! Jeg skriver et program i C som skal lese en inputfil med en bestemt form. Denne inputfilen skal lese inn en rekke tall som den bruker i videre beregninger. Det er derfor veldig viktig at det som står i inputfilen er et tall. Jeg er på utkikk etter en måte å validere denne inputfilen og sjekke at det som leses inn faktisk er tall. Måten jeg leser fra filen på er ganske enkelt: fscanf(fp, "%f %f %f\n", &lek->D[i], &lek->Br[i], &lek->L[i]); Jeg tenkte å løse det slik at dersom det som leses inn ikke er et tall så avsluttes programmet, eller at brukeren må skrive inn et gyldig tall. Jeg har tenkt ut to måter å løse dette på. Enten må jeg finne/skrive en funksjon som sjekker om inputen er float eller int. Eller at jeg setter en grense mellom 0 og max (Det er ikke snakk om store tall) og sjekker om inputen er mellom disse to. Siste løsning er selvsagt enkel, men den mest fleksible hadde selvsagt vært første. Det vil si noe slikt: while(is_numeric(lek->Br[i]) != 1) { printf("Tallet er ikke gyldig! Skriv inn nytt: "); scanf("%f", lek->Br[i]); //evt exit(EXIT_FAILURE); } Finnes dette? Jeg vet ctype.h har en del funksjoner, men jeg finner ikke ut av hvilken som løser mitt problem. Christian_ Lenke til kommentar
Alexen Skrevet 20. mars 2012 Del Skrevet 20. mars 2012 kanskje isdigit kan hjelpe deg? Lenke til kommentar
MisterIT Skrevet 20. mars 2012 Del Skrevet 20. mars 2012 Pleide å bruke atof() funksjonen for dette i C++, mener den skal også fungere greit i C http://www.codecogs.com/reference/computing/c/stdlib.h/atof.php Lenke til kommentar
zotbar1234 Skrevet 22. mars 2012 Del Skrevet 22. mars 2012 Jeg er på utkikk etter en måte å validere denne inputfilen og sjekke at det som leses inn faktisk er tall. Måten jeg leser fra filen på er ganske enkelt: fscanf(fp, "%f %f %f\n", &lek->D[i], &lek->Br[i], &lek->L[i]); Jeg tenkte å løse det slik at dersom det som leses inn ikke er et tall så avsluttes programmet, eller at brukeren må skrive inn et gyldig tall. Så inputen er interaktiv? Jeg har tenkt ut to måter å løse dette på. Enten må jeg finne/skrive en funksjon som sjekker om inputen er float eller int. Vil du ha float eller int? Hvis du vil ha begge, er "3" float eller int? Hva med "3.0"? Eller at jeg setter en grense mellom 0 og max (Det er ikke snakk om store tall) og sjekker om inputen er mellom disse to. Siste løsning er selvsagt enkel, men den mest fleksible hadde selvsagt vært første. Det vil si noe slikt: while(is_numeric(lek->Br[i]) != 1) { printf("Tallet er ikke gyldig! Skriv inn nytt: "); scanf("%f", lek->Br[i]); //evt exit(EXIT_FAILURE); } Finnes dette? Ja, men ikke slik du har lagt opp. Problemet med fscanf() med venner er at du ikke aner hvor eksakt i inputstrømmen den stoppet. Dvs. at det er vanskelig å rulle inputstrømmen til en kjent tilstand, sett fra programmets side. En kanonisk måte å gjøre inputvalidering på er: 1) Lese input i faste blokker (f.eks. 1 linje av gangen). 2) Validere en blokk av gangen. Hvis valideringen feiler, så vet du at inputstrømmen er i en veldefinert tilstand og du, i verste fall, kaster kun den defekte blokken. I dette tilfellet er det kanskje mest aktuelt å lese linjevis -- fgets() for å ta tak i linjen, og sscanf() for å tolke linjen. Du kan bruke strtod/strtof, men hvorfor ikke la sscanf() gjøre jobben? Spesielt hvis det er flere tall per linje? Lenke til kommentar
GeirGrusom Skrevet 26. mars 2012 Del Skrevet 26. mars 2012 Det er ikke kjempevanskelig å matche om tekst et tall manuelt heller. Lenke til kommentar
Valkyrex Skrevet 27. mars 2012 Del Skrevet 27. mars 2012 (endret) Posta litt før jeg så du holdt på i C og ikke C++, men men =) Og denne editoren likte ikke tabs -.- (ref kode utsende) En tungvint måte å gjøre det litt "robust" men veldig manuelt på. // -------------------- LES INN TALL ------------------------------------------ int lesTall(char* msg, int min, int max, bool returnIsZero) { int i, j; // For loop iterratorer int tempTall; // Et siffer som trekkes ut fra teksten int result; // Det endelige tallet char buffer[sTRLEN+1]; // Buffer for innlesning av input bool goodInput; // Om input var tall while (true) { // Loop intill vi har et godkjent tall result = 0; goodInput = true; cout &--#60;&--#60; msg; // Skriver ut meldingen cin.getline(buffer, STRLEN); // Så les inn input // Noen steder i programmet så har brukeren mulighet til å trykke enter // og det skal telle som verdien null. Her så sjekkes det om // "returnIsZero" boolen er true, samt at brukeren bare ga enter som // input, da breaket vi ut, og returerer result (som er setti til 1) if (returnIsZero && strlen(buffer) == 0) { break; } else { // Hvis ENTER ikke er lov if (strlen(buffer) == 0) { // Sjekk streng lengden goodInput = false; // Hvis den er null, så er den bad } else { // Hvis len &--#62; 0 så sjekkes hvert tegn // Her loopes det igjennom hvert eneste tegn i strengen, og // sjekker om den er mellom ascii verdiene til 0 og 9 for (i = 0; i &--#60; strlen(buffer); i++) { if ((int)buffer[i] &--#60; int("0") || (int)buffer[i] &--#62;int("9")){ goodInput = false; break; } } } if (goodInput) { // Om bruker input var tall og god // Loop igjennom hvert tegn og gjør om til tall (integer) for (i = strlen(buffer) - 1, j = 0; i &--#62;= 0; i--, j++) { tempTall = int(buffer[j])- 48; result += tempTall * (int)pow(10.0, (double)i); } if (result &--#62;= min && result &--#60;= max) { break; // Hvis innenfor riktig område } } } } return result; // Returner innlest tall } og en litt mindre tungvinn måte: // -------------------- SIKKER INNLESING AV TALL ------------------------------ int les_tall(char* msg) { int temp_tall; // Midlertidig int for å holde på tall while (true) { // Loop uendelig, intill "break" cout &--#60;&--#60; "\n" &--#60;&--#60; msg; // Skriv ut melding cin.unsetf(ios::skipws); // IKKE ignorer whitespace cin &--#62;&--#62; temp_tall; // Les inn tall if (cin.good()) { // Hvis god input cin.ignore(20, '\n'); // Ignorer break; // Og break ut av loopen } cin.clear(); // Clear Errpr Flags cin.ignore(20, '\n'); // Ignore } return temp_tall; // Returner en gyldig int } Endret 27. mars 2012 av Valkyrex Lenke til kommentar
LonelyMan Skrevet 14. mai 2012 Del Skrevet 14. mai 2012 Dette er årsaker til at man konstruerer filformater. Slike ting skal ikke løses i kode, men i design. Feil fremgangsmåte. Lenke til kommentar
LostOblivion Skrevet 2. juni 2012 Del Skrevet 2. juni 2012 (endret) Jepp, som LonelyMan sier. Om du skal teste dette for alle filer, blir det fort unødvendig komplisert. Et enkelt forebyggende mot feil, eller korrupterte filer, er å inkludere et "magic number" i starten av filformatet ditt, som sannsynligvis indikerer at det er riktig filtype. For Java's .class-filer som skal leses av JVM, er dette tallet CAFEBABE (i hex); i PNG-filer er det 89504E470D0A1A0A (i hex). Når du lager en ny fil, legger du alltid dette tallet i starten av filen, og tilsvarende sjekker du alltid at dette tallet stemmer når du skal lese filen. http://en.wikipedia....8programming%29 Edit: Men for å ta meg selv litt i nakken, er nok ikke dette en løsning på problemet ditt. Om jeg var deg, ville jeg antatt at det som stod der var tall, og så gitt brukeren en feilmelding om lesingen feilet. Dette kan løses med f.eks. exceptions, men da må du i minste tilfelle bruke C++. Endret 2. juni 2012 av LostOblivion Lenke til kommentar
Valkyrex Skrevet 3. juni 2012 Del Skrevet 3. juni 2012 Tja, Python har exception handeling det også (http://docs.python.org/tutorial/errors.html). Kan sammenlignes med C++ sine Try og Catch keywords. (kan hende andre språk har det også) Magicnumber løser bare en initiell sjekk om det er "denne filen jeg lette etter" opplegg. Hjelper nada å ha en fil som har mista ganske mye integritet under f.eks sending via UDP eller noe (ja, dårlig eksemple, hehe), men at magicnumber fortsatt er intakt og på riktig plass. - Anta at filen er korrekt. - Fang opp feil underveis, og håndter de på riktig måte. =) Lenke til kommentar
LostOblivion Skrevet 3. juni 2012 Del Skrevet 3. juni 2012 Dette er C/C++-tråden. Tror ikke trådstarter er interessert i å begynne med Python bare slik at han kan få exception handling for problemstillingen sin. På en annen side kan en nok også si at han nok ikke er interessert i å begynne med C++ for å få exception handling... Lenke til kommentar
Christian_ Skrevet 4. juni 2012 Forfatter Del Skrevet 4. juni 2012 Spørsmålet var i forbindelse med et skoleprosjekt. Jeg løste problemet ved å sjekke om en innlesing ble gyldig. Dvs noe slikt: error = fscanf(fp,"%f",&number); if(error != 1){printerror();} Dette fungerte tilfredsstillende, men det finnes sikkert mange andre måter å gjøre dette bedre på. Fristen for prosjektet er ute for lenge siden så for meg er problemet løst! Takk for hjelpen! Christian Lenke til kommentar
LonelyMan Skrevet 20. juni 2012 Del Skrevet 20. juni 2012 (endret) Ja som LostOblivion sa, å ha et magic number i fila som kjennetegner din fil er utmerket. Kjennetegnet bør være 4 bytes slik at du kan laste den inn i en dword type variabel og sjekke alle 4 bytene samtidig. Etter dette magiske kjennetegnet kan du ha 2-3 eller 4 hasher i tillegg, hvis det første magiske nummeret passerer og godkjennes, så kan du sjekke de 3-4 hashene du har som er like etter det magiske nummeret, dette for å virkelig være skråsikker på at filen er din fil. Du kan bruke 3 MD5 hasher, som burde være evig nok. Etter hashene kan du lagre et tall som forteller størrelsen på innholdet i filen etter det magiske tallet og hashene og eventuelt antall poster som er i filen. Etter dette kan du lagre poster. Her er en robust måte å verifisere filen, i kronologisk rekkefølge: 1: Sjekk at filen eksisterer, hvis ikke, avslutt 2: Sjekk at filstørrelsen er minst MAGICNUMBER+3HASHES i størrelse, hvis ikke, avslutt 3: Sjekk MAGICNUMBER, hvis ikke matcher, avslutt 4: Sjekk alle 3 hashene, hvis ikke matcher, avslutt 5: Sjekk at størrelsen på filen (MINUS) headerdata er riktig, hvis ikke, avslutt 6: Prosesser filen hvis du kom hit. Alt virker ok. Endret 20. juni 2012 av LonelyMan Lenke til kommentar
Valkyrex Skrevet 20. juni 2012 Del Skrevet 20. juni 2012 Gjør det litt vanskelig da Enklere å bare: - Når filen lages så slenges en checksum (f.eks md5 eller hva nå enn) av filen på enden. - Når filen leses så sjekkes det om checksumen fra fila, og checksumen av selve fila er like (da ser du om fila har tapt integritet under lagring / flytting / behandling). Lenke til kommentar
LonelyMan Skrevet 20. juni 2012 Del Skrevet 20. juni 2012 CheckSum er praktisk når du skal bruke alle dataene i filen, men ikke hvor du trenger bare deler av filen, enkelte poster. Da kan det lønne seg å oppdatere en egen post for størrelsen for hver post som legges til. Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå