Star_Light Δημοσ. 25 Νοεμβρίου 2013 Δημοσ. 25 Νοεμβρίου 2013 #include<stdio.h> #include<string.h> #include<ctype.h> #define MAXLEN 40+1 void tokenizer(char *str); int main(void) { char str[MAXLEN]={'\0'}; printf("Give your sentence: "); fgets(str , MAXLEN , stdin); tokenizer(str); return 0; } void tokenizer(char *str) { char *res = NULL; char delims[]={" !.#@?,></()+*-_"}; int i=0 , count=0; while( !isalpha(str[i])) { if(str[0] == '\n') return; i++; } res = strtok(str, delims ); while( res != NULL ){ printf("\n>%s" ,res); res = strtok(NULL , delims); count++; } for(; i<MAXLEN; i++) { if(!isalpha(str[i]) && str[i] ) { printf("%c\n" , str[i]); count++; } } printf(" Number of tokens is %d " , count); return; } Θέλω να φτιάξω εναν C string tokenizer που σπάει μια προταση που θα του δωσει ο χρηστης σε tokens και θα υπολογιζει τον αριθμο τους για παράδειγμα : HELLO/TO ALL!HOW ARE YOU??? 14 tokens HELLO TO ALL HOW ARE YOU / <space> ! <space> <space> ? ? ? Το προγραμμα οταν το τρεχω μου δινει τιμή 10. Η σκέψη μου ειναι αρχικα να χρησιμοποιησω την strtok ωστε να σπασει τις λέξεις της προτασης και στην συνεχεια να μετρησω εγω ποιοι χαρακτηρες δεν ειναι της αλφαβητου να τους υπολογισω ξεχωριστα να τους εκτυπωσω και μετα να προσθέσω το πληθος τους στην αρχικη count. Για καποιο λογο ομως δεν μου δουλευει σωστα το προγραμμα ουτε μου εκτυπωνει τους χαρακτηρες που θέλω.
bird Δημοσ. 25 Νοεμβρίου 2013 Δημοσ. 25 Νοεμβρίου 2013 Δεν έχω χρόνο να το δω, αλλά δεν μηδενίζεις το i στο for ενώ έχει πάρει κάποια τιμή όταν φεύγει από την πρώτη while...
Star_Light Δημοσ. 25 Νοεμβρίου 2013 Μέλος Δημοσ. 25 Νοεμβρίου 2013 Δεν έχω χρόνο να το δω, αλλά δεν μηδενίζεις το i στο for ενώ έχει πάρει κάποια τιμή όταν φεύγει από την πρώτη while... Ναι. Αυτο γινεται μονο στην περιπτωση που ο χρηστης δωσει κατι της μορφης ******HELLO HOW ARE YOU???? Οποτε τα αρχικα που δεν ειναι γραμματα της αλφαβήτου θελω να τα κανω reject. Οπως και την περίπτωση ο χρηστης απλα να πατησει μονο το ENTER στην αρχή.
ZAKKWYLDE Δημοσ. 25 Νοεμβρίου 2013 Δημοσ. 25 Νοεμβρίου 2013 Η strtok είναι destructive, που σημαίνει ότι θα αντικαταστήσει τους delimiter με null terminators. Παράλληλα έχεις δηλώσει το "string" σου ως char *str και μετά το γεμίζεις με fgets. Δεν ξέρω αν αυτό το ορίζει και ως const όπως αν έκανες char *str = "hello"; κοίταξέ το. Πιθανότατα η πηγή των προβλημάτων σου είναι το πρώτο. 1
migf1 Δημοσ. 25 Νοεμβρίου 2013 Δημοσ. 25 Νοεμβρίου 2013 Καλημέρα, εμένα με μπέρδεψες. Οι delimiters δεν γίνεται να είναι και tokens (εκτός αν τους έχεις escaped ανάμεσα σε unescaped delimiters, περίπτωση κατά την οποία δεν αρκεί η strtok(). Οπότε στο παράδειγμά σου, με το string που διαβάζεις (και που δεν του αφαιρείς το \n) και τους delimiters που δίνεις, τα tokens είναι τα παρακάτω: HELLO TO ALL HOW ARE YOU <\n> Αν είμαστε εντάξει μέχρι εδώ, πες τι θέλεις να κάνεις περαιτέρω.
imitheos Δημοσ. 25 Νοεμβρίου 2013 Δημοσ. 25 Νοεμβρίου 2013 Καλημέρα, εμένα με μπέρδεψες. Οι delimiters δεν γίνεται να είναι και tokens (εκτός αν τους έχεις escaped ανάμεσα σε unescaped delimiters, περίπτωση κατά την οποία δεν αρκεί η strtok(). +1 Tokens είναι αυτά που είναι ανάμεσα στους delimiters. Εκτός από την strtok, ένας από τους δεκάδες τρόπους να γίνει non-destructively είναι η χρήση των str*spn (εδώ συγκεκριμένα της strcpsn) στο περίπου όπως φαίνεται παρακάτω. while (*str) { i = strcspn(str, delims); printf("%.*s\n",i, str); str += i; count++; str++; } Η strcspn επιστρέφει το μεγαλύτερο μήκος string που δεν περιέχει κανένα από τους delimiters. Στην είσοδο του παραδείγματος εμφανίζεται HELLO TO ALL HOW ARE YOU Number of tokens is 8 Άσχετο αλλά ο έλεγχος για newline στο str[0] γιατί είναι μέσα στο while ? Μπορεί στους 3 πρώτους ελέγχους το str[0] να μην έχει newline και στον 4ο έλεγχο να εμφανίσει ? 1
defacer Δημοσ. 25 Νοεμβρίου 2013 Δημοσ. 25 Νοεμβρίου 2013 Αν δεν είμαστε παντρεμένοι με τη χρήση της strtok (που απ' ότι βλέπω από το πρώτο post δεν είμαστε) τότε γιατί δεν μπορούν οι delimiters να λογίζονται ως tokens μήκους 1? Προφανώς και γίνεται, για παράδειγμα το regular expression /[ !.#@?,></()+*_-]|[^ !.#@?,></()+*_-]+/g κάνει ακριβώς 14 matches όπως θέλει ο Starlight. Με τις str©spn και ένα loop θα μπορούσε να γίνει πανεύκολα. 1
migf1 Δημοσ. 25 Νοεμβρίου 2013 Δημοσ. 25 Νοεμβρίου 2013 Αν δεν είμαστε παντρεμένοι με την strtok() προφανώς και μπορούμε να διαχειριστούμε το string και τους χαρακτήρες του όπως θέλουμε, το είπαμε από την αρχή. Π.χ. με 2-3 γραμμές κώδικα παραπάνω από αυτόν που έδωσε ο ημίθεος μετράμε και τους delimiters ως tokens, τα οποία btw είναι 15 μιας και υπάρχει και ένα τελικό '\n' στο παράδειγμα του starlight... ... char str[MAXLEN] = "HELLO/TO ALL!HOW ARE YOU???\n"; char *delims = " !.#@?,></()+*-_"; int count = 0; for (char *cp = str; cp && *cp;) { int i = strspn(cp, delims); for (int k=0; k < i; k++) { printf( "%d: %c\n", count, cp[k] ); count++; } cp += i; int j = strcspn(cp, delims); printf("%d: %.*s\n", count, j, cp); cp += j; count++; } printf( "\ntokens count: %d\n", count ); ... * μπορεί να περιέχει κάνα bug, δεν το δοκίμασα extensively Γενικώς όμως όταν λέμε tokens δεν λογίζουμε τους delimiting characters.
Star_Light Δημοσ. 25 Νοεμβρίου 2013 Μέλος Δημοσ. 25 Νοεμβρίου 2013 Καλημέρα, εμένα με μπέρδεψες. Οι delimiters δεν γίνεται να είναι και tokens (εκτός αν τους έχεις escaped ανάμεσα σε unescaped delimiters, περίπτωση κατά την οποία δεν αρκεί η strtok(). Οπότε στο παράδειγμά σου, με το string που διαβάζεις (και που δεν του αφαιρείς το \n) και τους delimiters που δίνεις, τα tokens είναι τα παρακάτω: HELLO TO ALL HOW ARE YOU <\n> Αν είμαστε εντάξει μέχρι εδώ, πες τι θέλεις να κάνεις περαιτέρω. Εντάξει είμαστε. Θέλω να λάβω υπόψιν σαν tokens και τα άλλα σύμβολα. Πχ η γραμμη : HELLO_TO_ALL!HOW_ARE%%YOU??? Να αποτελειται απο τα HELLO _ TO _ ALL ! HOW _ ARE %% YOU ??? δηλαδη 15 tokens. Απο οσο ειδα μαλλον θα πρεπει να βρω και μια άλλη έτοιμη συνάρτηση απο την C. Oποτε θα ψάξω. Ευχαριστω για τους κώδικες αλλα δεν θελω να πάρω έτοιμο αυτη τη φορα θελω να το φτιάξω μονος μου. Delimiters ειναι πχ τα _ ! % και ? παραπανω? θελω να τα μετράει ολα να κανει κανονικη αναλυση της εισοδου.
migf1 Δημοσ. 25 Νοεμβρίου 2013 Δημοσ. 25 Νοεμβρίου 2013 Δες τότε τις 2 που είπαμε, καθώς επίσης τις strpbrk(), strstr(), strchr() και strrchr(). Από εκεί και πέρα, ανάλογα την πλατφόρμα υπάρχουν κι άλλες μη-στάνταρ. http://pubs.opengroup.org/onlinepubs/007908775/xsh/string.h.html 1
Star_Light Δημοσ. 25 Νοεμβρίου 2013 Μέλος Δημοσ. 25 Νοεμβρίου 2013 Eγινε. Ευχαριστώ. Θα τις δώ και θα ποστάρω μολις τελειώσω για κριτικές και βελτιώσεις. 1
Star_Light Δημοσ. 26 Νοεμβρίου 2013 Μέλος Δημοσ. 26 Νοεμβρίου 2013 (επεξεργασμένο) Τελικά σημερα που ειχα χρονο έκατσα και σκέφτηκα έναν αλγοριθμο που χρησιμοποιει ένα loop και απο έτοιμες συναρτήσεις χρησιμοποιώ στην υλοποιηση strtok και strlen. ΑΡΧΗ_ΕΠΑΝΑΛΗΨΗΣ ΑΝ Ο ΧΑΡΑΚΤΗΡΑΣ ΓΡΑΜΜΗΣ ΕΙΣΟΔΟΥ ΔΕΝ ΕΙΝΑΙ ΓΡΑΜΜΑ ΑΛΦΑΒΗΤΟΥ ΑΥΞΗΣΕ ΜΕΤΡΗΤΗ ΣΤΟΙΧΕΙΩΝ ΚΑΤΑ 1 ΑΥΞΗΣΕ ΜΕΤΡΗΤΗ ΠΙΝΑΚΑ ΚΑΤΑ 1 ΤΕΛΟΣ ΑΝ ΑΛΛΙΩΣ ΑΝ Ο ΧΑΡΑΚΤΗΡΑΣ ΤΗΣ ΓΡΑΜΜΗΣ ΕΙΝΑΙ ΓΡΑΜΜΑ ΑΛΦΑΒΗΤΟΥ ΑΥΞΗΣΕ ΤΟΝ ΜΕΤΡΗΤΗ ΤΩΝ ΛΕΞΕΩΝ ΚΑΤΑ 1 ΑΥΞΗΣΕ ΤΟΝ ΜΕΤΡΗΤΗ ΤΟΥ ΠΙΝΑΚΑ ΚΑΤΑ ΤΟ ΜΗΚΟΣ ΤΗΣ ΛΕΞΗΣ ΤΕΛΟΣ ΑΛΛΙΩΣ ΑΝ ΑΝ Η ΓΡΑΜΜΗ ΕΙΣΟΔΟΥ ΒΡΙΣΚΕΤΑΙ ΣΤΟ ΤΕΛΟΣ ΤΗΣ ΒΓΕΣ ΑΠΟ ΤΗΝ ΕΠΑΝΑΛΗΨΗ ΤΕΛΟΣ ΑΝ ΤΕΛΟΣ ΕΠΑΝΑΛΗΨΗΣ ΕΚΤΥΠΩΣΕ ΜΕΤΡΗΤΗΣ ΣΤΟΙΧΕΙΩΝ + ΜΕΤΡΗΤΗΣ ΛΕΞΕΩΝ #include<stdio.h> #include<string.h> #include<ctype.h> #include<stdbool.h> #define MAXLEN 40+1 void line_tokenizer(char *str); int word_tokenizer(char *str); int main(void) { char str[MAXLEN]={'\0'}; printf("Give your sentence: "); fgets(str , MAXLEN , stdin); line_tokenizer(str); return 0; } void line_tokenizer(char *str) { int i = 0 , count_items = 0 , count_words = 0 ; for(;{ if(!isalpha(str[i])) { count_items++; printf("%c\n" , str[i]); i++; } else if( isalpha(str[i]) ){ count_words++; i += word_tokenizer(str+i); } if( str[i] == '\n' || i > MAXLEN){ break; } } printf("Number of tokens: %d", count_items+count_words); return; } int word_tokenizer(char *str) { char *res = NULL; char delims[]=" !.#@?,></()+*-_\n$%^=&@"; res = strtok(str,delims); printf("%s", res); return strlen(res); } Eλεος με τα tags για code του φορουμ αλλη φορα θα το βαζω σε pastebin μου εχει σβηστει το μηνυμα τοσες φορες και αναγκαζομαι να ξαναγραφω τωρα. INPUT: ***HELLO%%MAN. Number of Tokens : 8 Aπλα μενει να εκτυπωσω και τα tokens τωρα ολα μαζι μονο διπλα απο τα HELLO και MAN μου ξεφευγουν οι χαρακτηρες επειδη η strok θετει σε '\0' αυτους τους delimiters. EDIT : Τωρα το ειδα εχει και αλλα θέματα που θα κοιταξω αυριο EDIT 2: Τελικα η strtok μου δημιουργει προβληματα και σε αλλους εισοδους οπως ΗΙ ΜΑΝ σκετο δεν ξερω μπορει και να την αλλαξω ηθελα απλα μια συνάρτηση να επιστρέφει το μηκος των λέξεων στην προταση ωστε να αυξανω μετα τοn counter με βαση αυτο το μήκος. EDIT 3: (Ελπιζω και τελευταιο) Άλλαξα την strtok με την strcspn πιστευω ειναι οκ τωρα int word_tokenizer(char *str) { char delims[]=" !.#@?,></()+*-_\n$%^=&@"; return strcspn(str , delims); } Επεξ/σία 27 Νοεμβρίου 2013 από Star_Light
Star_Light Δημοσ. 28 Νοεμβρίου 2013 Μέλος Δημοσ. 28 Νοεμβρίου 2013 Έκανα κάποιες διορθώσεις στον κώδικα η μια συναρτηση δεν χρειαζοταν οποτε την έβγαλα : http://pastebin.com/774s5EP3 Δεν βάζω να μετραει και το ENTER σαν token. Τελοςπαντων σκεφτομαι τωρα να το βαζω να εμφανίζει και τα συμβολα αλλα και τις λέξεις ξεχωριστά. Σκεφτομαι να χρησιμοποιησω την strtok μετα την εξοδο απο τον βροχο που θα εχει γινει η δουλεια και δεν θα με χαλασει πλεον να βάζει τον '\0' στους χαρακτήρες που χωριζουν τις λέξεις. Αυτο ομως απο οτι αντιλαμβανομαι δεν θα βοηθαει και πολυ στο αν θα χρειαστεί μετα να χρησιμοποιησεις την γραμμή εισοδου κάπου αλλου στο προγραμμα με αλλα λογια η συνάρτηση μαλλον δεν θα ειναι επαναχρησιμοποιησιμη. Καμια καλυτερη προταση στο πως θα εμφανιζω μια μια τις λέξεις της γραμμής?
migf1 Δημοσ. 28 Νοεμβρίου 2013 Δημοσ. 28 Νοεμβρίου 2013 Αν έχεις έναν destructive tokenizer και θέλεις να διατηρήσεις το αρχικό σου string, μπορείς να περάσεις στον tokenizer ένα αντίγραφο του αρχικού σου string (π.χ. με την strdup() ή φτιάχνοντάς την αν δεν την παρέχει η βιβλιοθήκη του vendor σου). Από εκεί και πέρα, όπως έχω ήδη αναφέρει, δυσκολεύομαι να αντιληφθώ τη χρησιμότητα ενός tokenizer που θεωρεί ως tokens και τα delimiting characters. Επίσης, ένας tokenizer για να είναι χρήσιμος πρέπει να επιστρέφει τα tokens (είτε ένα-ένα για χρήση τους σε κάποιον προοδευτικό αλγόριθμο, όπως κάνει π.χ. η strtok) είτε όλα μαζί σε κάποιου είδους δομή για περαιτέρω επεξεργασία των tokens (π.χ. σε έναν πίνακα, μια λίστα, κλπ).
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα