Merkkijonon jäsentäminen C

Tämän oletetaan olevan tiukka ANSI C89-pedanttinen koodi. Sen tulisi purkaa word1, word2 ja word3 merkkijonosta, joka on muotoiltu [word1] word2 [ word3] ja palautusvirhe missä tahansa muussa muodossa.

Se näyttää toimivan, mutta se näyttää niin rumalta. Ei tarvitse kommentoida tosiasiaa, että GetTokenBetweenSquareBraces ja GetTokenBtweenOpositeSquareBraces ovat kaksoiskappaleita.

Haluaisin mielelläni vinkkejä puhdista tämä.

#include <stdio.h> #include <string.h> #include <ctype.h> char * TrimWhiteSpaces(char *str) { char *out = str; int i; int len = strlen(str); for (i=0; i<len && isspace(str[i]); i++, out++); /*scan forward*/ for (i=len-1; i>=0 && isspace(str[i]); str[i]=0, i--);/*scan backward*/ return out; } char * GetTokenBetweenSquareBraces(char * input, char **output, int * output_size) { char *p = TrimWhiteSpaces(input); *output_size=0; if (p[0] == "[") { *output = TrimWhiteSpaces(p + 1); do { (*output_size)++; }while((*output)[*output_size] != "]" && isalnum((*output)[*output_size])); } else { return NULL; } return (*output) + *output_size; } char * GetTokenBtweenOpositeSquareBraces(char * input, char **output, int * output_size) { char *p = TrimWhiteSpaces(input); *output_size=0; if (p[0] == "]") { *output = TrimWhiteSpaces(p + 1); do { (*output_size)++; }while((*output)[*output_size] != "[" && isalnum((*output)[*output_size])); } else { return NULL; } return (*output) + *output_size; } int GetWords(char * str,char * word1,char * word2,char * word3) { char * next=NULL,*output=NULL; int outputsize; printf ("\nSplitting string \"%s\" into tokens:\n",str); next = GetTokenBetweenSquareBraces (str,&output,&outputsize); strncpy(word1,output,outputsize); word1[outputsize] = "\0"; strcpy(word1,TrimWhiteSpaces(word1)); if(!next) return 0; next = GetTokenBtweenOpositeSquareBraces (next,&output,&outputsize); strncpy(word2,output,outputsize); word2[outputsize] = "\0"; strcpy(word2,TrimWhiteSpaces(word2)); if(!next) return 0; next = GetTokenBetweenSquareBraces (next,&output,&outputsize); strncpy(word3,output,outputsize); word3[outputsize] = "\0"; strcpy(word3,TrimWhiteSpaces(word3)); if(!next) return 0; return 1; } void TestGetWords(char * str ) { char word1[20],word2[20],word3[20]; if (GetWords(str,word1,word2,word3)) { printf("|%s|%s|%s|\n",word1,word2,word3); } else { printf("3ViLLLL\n"); } } int main (void) { char str[] ="[ hello ] gfd [ hello2 ] "; char str2[] ="[ hello [ gfd [ hello2 ] "; char str3[] ="the wie321vg42g42g!@#"; char str4[] ="][123[]23][231["; TestGetWords(str); TestGetWords(str2); TestGetWords(str3); TestGetWords(str4); getchar(); return 1; } 

Kommentit

  • Korjaa sisennys ensin. Markdown-moottori ei ’ tykkää välilehdistä – korvaa ne välilyönneillä.
  • @LokiAstari: näyttää siltä, että olet vaihtanut hänen alkuperäisen koodinsa.
  • Opps. Anteeksi. Korjasin ruuvini toivottavasti. Sain koodin meta-artikkelista. korjasi välilehden ongelman ja asetti sen takaisin. Jos tämä ei ole oikein, olen pahoillani, mutta en voi ’ näyttää näyttävän palauttavan versiota.
  • @LokiAstari: Kyllä, näyttää paljon paremmalta.

vastaus

#include <stdio.h> #include <string.h> #include <ctype.h> char * TrimWhiteSpaces(char *str) { char *out = str; int i; int len = strlen(str); for (i=0; i<len && isspace(str[i]); i++, out++); /*scan forward*/ 

Minulla on ainakin runko kommentti täällä. Sen puolipiste on helppo jättää väliin. En usko, että tarvitset testiä i < len. Merkkijonon lopussa olevan nollan pitäisi epäonnistua isspace -testissä, joten sinun ei tarvitse myöskään tarkistaa pituutta. Ei myöskään ole järkevää seurata i. Käytä sen sijaan vain out.

 for (i=len-1; i>=0 && isspace(str[i]); str[i]=0, i--);/*scan backward*/ 

Kaikkien näiden välien ei tarvitse olla 0. Kaiken kaikkiaan teet paljon työtä tällä yhdellä rivillä. Tee ainakin 0-asetus silmukan rungon sisällä, koska sillä ei ole mitään tekemistä silmukan ohjauksen kanssa.

 return out; 

Parasta on joko muokata parametreja tai palauttaa uusia. Älä tee molempia. Tässä palautat uuden merkkijonon osoittimen ja muokkaat alkuperäistä merkkijonoa.

} char * GetTokenBetweenSquareBraces(char * input, char **output, int * output_size) { char *p = TrimWhiteSpaces(input); *output_size=0; if (p[0] == "[") { *output = TrimWhiteSpaces(p + 1); do { (*output_size)++; }while((*output)[*output_size] != "]" && isalnum((*output)[*output_size])); 

] ei ole numero tai kirjain. Et tarvitse molempia testejä.

 } else { return NULL; } return (*output) + *output_size; } char * GetTokenBtweenOpositeSquareBraces(char * input, char **output, int * output_size) { char *p = TrimWhiteSpaces(input); *output_size=0; if (p[0] == "]") { *output = TrimWhiteSpaces(p + 1); do { (*output_size)++; }while((*output)[*output_size] != "[" && isalnum((*output)[*output_size])); } else { return NULL; } return (*output) + *output_size; } 

Deja Vu! Tämä on melkein täsmälleen sama kuin edellinen toiminto. Vain suluissa olevat suunnat on vaihdettu. Vaikuttaa siltä, että sinun pitäisi pystyä jakamaan kyseinen koodi.

int GetWords(char * str,char * word1,char * word2,char * word3) { char * next=NULL,*output=NULL; int outputsize; printf ("\nSplitting string \"%s\" into tokens:\n",str); 

Yleensä suosittelen, ettet anna toimintojesi suorittaa mitään tulostusta. Pariton valinta myös rivien sijoittamiseen.

 next = GetTokenBetweenSquareBraces (str,&output,&outputsize); strncpy(word1,output,outputsize); word1[outputsize] = "\0"; strcpy(word1,TrimWhiteSpaces(word1)); 

Miksi trimmaat tyhjää tilaa täällä? Etkö jo tehnyt niin. Teet paljon työtä kopioidaksesi tekstiä. Ehkä se on jotain, jonka GetTokenBetweenSquareBraces olisi pitänyt tehdä?

 if(!next) return 0; next = GetTokenBtweenOpositeSquareBraces (next,&output,&outputsize); strncpy(word2,output,outputsize); word2[outputsize] = "\0"; strcpy(word2,TrimWhiteSpaces(word2)); if(!next) return 0; 

Deja Vu!

 next = GetTokenBetweenSquareBraces (next,&output,&outputsize); strncpy(word3,output,outputsize); word3[outputsize] = "\0"; strcpy(word3,TrimWhiteSpaces(word3)); if(!next) return 0; 

Deja Vu!

 return 1; } void TestGetWords(char * str ) { char word1[20],word2[20],word3[20]; 

Koodisi ei ole varovainen varmistaaksesi, että et ylitä näitä muuttujia. Haluat ehkä tehdä jotain

 if (GetWords(str,word1,word2,word3)) { printf("|%s|%s|%s|\n",word1,word2,word3); } else { printf("3ViLLLL\n"); } } int main (void) { char str[] ="[ hello ] gfd [ hello2 ] "; char str2[] ="[ hello [ gfd [ hello2 ] "; char str3[] ="the wie321vg42g42g!@#"; char str4[] ="][123[]23][231["; TestGetWords(str); TestGetWords(str2); TestGetWords(str3); TestGetWords(str4); 

Automaattisen testauksen kannalta on parempi, jos annat oikean vastauksen ja tarkistat vastauksen koodissa. Tällä tavoin ohjelma ilmoittaa, kun se on väärin.

 getchar(); return 1; 

0 käytetään osoittamaan onnistunutta ohjelman ajamista.

} 

Ohjelmasi on kaiken kaikkiaan ruma, koska käytät väärää sanastoa. Olet käyttänyt sanastoa annettuna sen sijaan, että määrittäisit sanaston, joka teki tehtävän kuvaamisen helpoksi. Tässä on lähestymistapa ongelmasi

char * Whitespace(char * str) /* This function return the `str` pointer incremented past any whitespace. */ { /* when an error occurs, we return NULL. If an error has already occurred, just pass it on */ if(!str) return str; while(isspace(*str)) { str++; } return str; } char * Character(char * str, char c) /* This function tries to match a specific character. It returns `str` incremented past the character or NULL if the character was not found */ { if(!str) return str; /* Eat any whitespace before the character */ str = Whitespace(str); if(c != *str) { return NULL; } else { return str + 1; } } char * Word(char * str, char * word) /* This function reads a sequence of numbers and letter into word and then returns a pointer to the position after the word */ { /* Handle errors and whitespace */ if(!str) return str; str = Whitespace(str); /* copy characters */ while(isalnum(*str)) { *word++ = *str++; } *word = 0; /* don"t forget null!*/ return str; } int GetWords(char * str,char * word1,char * word2,char * word3) { str = Character(str, "["); str = Word(str, word1); str = Character(str, "]"); str = Word(str, word2); str = Character(str, "["); str = Word(str, word3); str = Character(str, "]"); str = Character(str, "\0"); return str != NULL; } 

Mitä minä ” Olemme tehneet (tai yrittäneet) kirjoittaa Character-, Whitespace- ja Word-funktiot siten, että ne ovat todella yksinkertaisia. Jos ymmärrät char *, sinun ei pitäisi olla mitään ongelmia heidän kanssaan. Mutta nämä yksinkertaiset työkalut yhdistyvät erittäin hienosti, jotta jäsentimesi voidaan toteuttaa suoraviivaisesti.

Kommentit

  • +1 sarakkeelle ” Yleensä suosittelen, ettet anna toimintojesi suorittaa mitään tulostusta ”. Myös erittäin mukava ja puhdas ratkaisu.

Vastaa

Tämä on ehkä vähän vähemmän ruma, mutta merkkijonon käsittely ei tule koskaan olemaan kaunista C: ssä.

static const char * skip_space(const char *s) { return s + strspn(s, " "); } static const char * skip_bracket(const char * s, int bracket) { s = skip_space(s); if (*s != bracket) return NULL; return skip_space(++s); } static const char * skip_word(const char * s) { return s + strcspn(s, " []"); } static const char * copy_word(char *w, const char *s, size_t size) { const char * end = skip_word(s); size_t len = end - s; if (len >= size) /* silently truncate word to buffer size */ len = size - 1; memcpy(w, s, len); w[len] = "\0"; return skip_space(end); } static int get_words(const char *s, char *w1, char *w2, char *w3, size_t size) { if ((s = skip_bracket(s, "[")) == NULL) return 0; s = copy_word(w1, s, size); if ((s = skip_bracket(s, "]")) == NULL) return 0; s = copy_word(w2, s, size); if ((s = skip_bracket(s, "[")) == NULL) return 0; s = copy_word(w3, s, size); if ((s = skip_bracket(s, "]")) == NULL) return 0; return 1; } 

Vastaa

Voit suorittaa tämän tehtävän tilakoneella.

#include <stdio.h> #include <string.h> void Tokenize(char* s) { // the following array return new state based on current state and current scanned char // Input: * [ ] space Print Tokenize Current State Expression /*Next state:*/char StateArray[12][3][4] = {{{11,1,11,0} ,{0,0,0,0},{0,0,0,0} }, //0 {space}*{[} {{2,11,11,1} ,{1,0,0,0},{0,0,0,0}}, //1 {space}*{char} {{2,11,4,3} ,{1,0,0,0},{0,0,1,0}}, //2 {char}*{space}?{]} {{11,11,4,3} ,{0,0,0,0},{0,0,1,0}}, //3 {space}*{]} {{5,11,11,4} ,{1,0,0,0},{0,0,0,0}}, //4 {space)*{char} {{5,7,11,6} ,{1,0,0,0},{0,1,0,0}}, //5 {char}*{space}?{[} {{11,7,11,6} ,{0,0,0,0},{0,1,0,0}}, //6 {space}*{[} {{8,11,11,7} ,{1,0,0,0},{0,0,0,0}}, //7 {space}*{char} {{8,11,10,9} ,{1,0,0,0},{0,0,1,0}}, //8 {char}*{space}?{]} {{11,11,10,9} ,{0,0,0,0},{0,0,1,0}}, //9 {space}*{]} {{11,11,11,10} ,{0,0,0,0},{0,0,0,0}}, //10 {space}* {{11,11,11,11} ,{0,0,0,0},{0,0,0,0}} }; char state=0; int len = strlen(s); for(int i =0;i<len;i++) { if(StateArray[state][1][(s[i]^91)? ((s[i]^93)?((s[i]^32)? 0:3):2):1]) printf("%c",s[i]); if(StateArray[state][2][(s[i]^91)? ((s[i]^93)?((s[i]^32)? 0:3):2):1]) printf("\n"); state=StateArray[state][0][(s[i]^91)? ((s[i]^93)?((s[i]^32)? 0:3):2):1]; switch(state) { case 11: printf("Error at column %d",i); case 10: if(i==len-1) { printf("\nParsing completed"); } } } } int main(void) { char* s= " [ word1 ] word2word [ 3 ] "; // test string Tokenize(s); } 

Kommentit

  • Hei, ja Tervetuloa Code Review -ohjelmaan. Tämä koodi ei todellakaan ole arvostelu. Pikemminkin se on vaihtoehtoinen tapa tehdä asioita, joilla on vähän selityksiä siitä, mitä se tekee, miksi se toimii ja miksi se on parempi kuin alkuperäinen. Lisäksi näytän t sen läpi ja huolehdi puuttuvista aaltosulkeista, kaatuneista tapauslausekkeista ja hämärtyvistä bittihoidoista, joita ei ole dokumentoitu. Harkitse lisää yksityiskohtia siitä, miksi tämä on parempi ja mitä se ratkaisee eri tavalla kuin toimenpideohjelma ja miksi nämä valinnat tekevät paremman koodin.
  • Loitko tämän käsin vai onko mukana jokin työkalu? Pidän konseptista, mutta ’ pelkään tämän tukemista. Maagisia numeroita on niin paljon.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *