Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.
#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. Για καποιο λογο ομως δεν μου δουλευει σωστα το προγραμμα ουτε μου εκτυπωνει τους χαρακτηρες που θέλω. 

Δημοσ.

Δεν έχω χρόνο να το δω, αλλά δεν μηδενίζεις το i στο for ενώ έχει πάρει κάποια τιμή όταν φεύγει από την πρώτη while...

Δημοσ.

Δεν έχω χρόνο να το δω, αλλά δεν μηδενίζεις το i στο for ενώ έχει πάρει κάποια τιμή όταν φεύγει από την πρώτη while...

 

Ναι. Αυτο γινεται μονο στην περιπτωση που ο χρηστης δωσει κατι της μορφης 

 

******HELLO HOW ARE YOU????

 

Οποτε τα αρχικα που δεν ειναι γραμματα της αλφαβήτου θελω να τα κανω reject. Οπως και την περίπτωση ο χρηστης απλα να πατησει μονο το ENTER στην αρχή.

Δημοσ.

Η strtok είναι destructive, που σημαίνει ότι θα αντικαταστήσει τους delimiter με null terminators. Παράλληλα έχεις δηλώσει το "string" σου ως char *str και μετά το γεμίζεις με fgets. Δεν ξέρω αν αυτό το ορίζει και ως const όπως αν έκανες char *str = "hello"; κοίταξέ το. Πιθανότατα η πηγή των προβλημάτων σου είναι το πρώτο.

  • Like 1
Δημοσ.

Καλημέρα,

 

εμένα με μπέρδεψες. Οι delimiters δεν γίνεται να είναι και tokens (εκτός αν τους έχεις escaped ανάμεσα σε unescaped delimiters, περίπτωση κατά την οποία δεν αρκεί η strtok().

 

Οπότε στο παράδειγμά σου, με το string που διαβάζεις (και που δεν του αφαιρείς το \n) και τους delimiters που δίνεις, τα tokens είναι τα παρακάτω:

HELLO
TO
ALL
HOW
ARE
YOU
<\n>

Αν είμαστε εντάξει μέχρι εδώ, πες τι θέλεις να κάνεις περαιτέρω.

Δημοσ.

Καλημέρα,

 

εμένα με μπέρδεψες. Οι 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ο έλεγχο να εμφανίσει ? :P
  • Like 1
Δημοσ.

Αν δεν είμαστε παντρεμένοι με τη χρήση της strtok (που απ' ότι βλέπω από το πρώτο post δεν είμαστε) τότε γιατί δεν μπορούν οι delimiters να λογίζονται ως tokens μήκους 1? Προφανώς και γίνεται, για παράδειγμα το regular expression

/[ !.#@?,></()+*_-]|[^ !.#@?,></()+*_-]+/g

κάνει ακριβώς 14 matches όπως θέλει ο Starlight. Με τις str©spn και ένα loop θα μπορούσε να γίνει πανεύκολα.

  • Like 1
Δημοσ.

Αν δεν είμαστε παντρεμένοι με την 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.

Δημοσ.

Καλημέρα,

 

εμένα με μπέρδεψες. Οι 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 ειναι πχ τα _ ! % και ? παραπανω? θελω να τα μετράει ολα να κανει κανονικη αναλυση της εισοδου. 

Δημοσ. (επεξεργασμένο)

Τελικά σημερα που ειχα χρονο έκατσα και σκέφτηκα έναν αλγοριθμο που χρησιμοποιει ένα 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);
}
Επεξ/σία από Star_Light
Δημοσ.

Έκανα κάποιες διορθώσεις στον κώδικα η μια συναρτηση δεν χρειαζοταν οποτε την έβγαλα :

 

http://pastebin.com/774s5EP3

 

Δεν βάζω να μετραει και το ENTER σαν token. Τελοςπαντων σκεφτομαι τωρα να το βαζω να εμφανίζει και τα συμβολα αλλα και τις λέξεις ξεχωριστά. Σκεφτομαι να χρησιμοποιησω την strtok μετα την εξοδο απο τον βροχο που θα εχει γινει η δουλεια και δεν θα με χαλασει πλεον να βάζει τον '\0' στους χαρακτήρες που χωριζουν τις λέξεις. Αυτο ομως απο οτι αντιλαμβανομαι δεν θα βοηθαει και πολυ στο αν θα χρειαστεί μετα να χρησιμοποιησεις την γραμμή εισοδου κάπου αλλου στο προγραμμα με αλλα λογια η συνάρτηση μαλλον δεν θα ειναι επαναχρησιμοποιησιμη. Καμια καλυτερη προταση στο πως θα εμφανιζω μια μια τις λέξεις της γραμμής?

Δημοσ.

Αν έχεις έναν destructive tokenizer και θέλεις να διατηρήσεις το αρχικό σου string, μπορείς να περάσεις στον tokenizer ένα αντίγραφο του αρχικού σου string (π.χ. με την strdup() ή φτιάχνοντάς την αν δεν την παρέχει η βιβλιοθήκη του vendor σου).

 

Από εκεί και πέρα, όπως έχω ήδη αναφέρει, δυσκολεύομαι να αντιληφθώ τη χρησιμότητα ενός tokenizer που θεωρεί ως tokens και τα delimiting characters.

 

Επίσης, ένας tokenizer για να είναι χρήσιμος πρέπει να επιστρέφει τα tokens (είτε ένα-ένα για χρήση τους σε κάποιον προοδευτικό αλγόριθμο, όπως κάνει π.χ. η strtok) είτε όλα μαζί σε κάποιου είδους δομή για περαιτέρω επεξεργασία των tokens (π.χ. σε έναν πίνακα, μια λίστα, κλπ).

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...