Επισκέπτης Δημοσ. 27 Οκτωβρίου 2010 Δημοσ. 27 Οκτωβρίου 2010 Καλησπέρα, Έχω γράψει ένα C function 'str_replace()' το οποίο, όπως υποδηλώνει και το όνομα αντικαθιστά ένα substring με κάποιο άλλο, μέσα σε ένα string. Σκοπός μου είναι το function να πληρεί τα εξής: Να μην κάνει δυναμική δέσμευση μνήμης (malloc) αλλά να δέχεται έναν buffer σαν είσοδο και να επιστρέφει εκεί το τελικό αποτέλεσμα. Να μην μπορεί σε καμία περίπτωση να γίνει overflow ο buffer (με την προϋπόθεση φυσικά ότι έχει δοθεί σωστά το μέγεθος του buffer σαν παράμετρος στην συνάρτηση). Ακόμα και αν το τελικό string είναι μεγαλύτερο από τον buffer που δόθηκε, να επιστρέφει όσους χαρακτήρες χωράνε και να δηλώνει το truncation επιστρέφοντας 0. Να κάνει αντικατάσταση σε όλα τα occurrences και όχι μόνο στο πρώτο που θα βρει. Ο destination buffer να είναι πάντα NULL terminated string. Όποιος έχει χρόνο/διάθεση να διαβάσει τον κώδικα της συνάρτησης και να κάνει σχόλια/παρατηρήσεις/προτάσεις για βελτίωση. Όλα ευπρόσδεκτα. Φυσικά δεν αποκλείεται να υπάρχουν ατέλειες και bugs, εάν δείτε κάποιο let me know > /** * Find and replace all occurences of org string with rep found in fmt, placing * the final result in buf. In case the destination buffer is not big enough * truncate the string (and return 0 instead of the resulting string's length). * * @param fmt const char * * @param org const char * * @param rep const char * * @param buf char * * @param buflen size_t * @return size_t */ size_t str_replace(const char *fmt, const char *org, const char *rep, char *buf, size_t buflen) { size_t newlen = 0; size_t tmp, fmtlen, orglen, replen; const char *s, *t; /* Prevent stupid calls. */ if (!fmt || !org || !rep || !buf) return 0; /* We will need these later. */ fmtlen = strlen(fmt); orglen = strlen(org); replen = strlen(rep); s = fmt; /* Iterate through all occurences. */ while ((t = strstr(s, org)) != NULL) { if ((tmp = t - s) < buflen) { memcpy(buf + newlen, s, tmp); newlen += tmp; } else { /* Just to return something. */ memcpy(buf + newlen, s, (buflen - 1) - newlen); buf[buflen - 1] = '\0'; return 0; } /* Move the pointer just after the org occurence. */ s = t + orglen; if (newlen + replen < buflen) { memcpy(buf + newlen, rep, replen); newlen += replen; } else { /* Just to return something. */ memcpy(buf + newlen, rep, (buflen - 1) - newlen); buf[buflen - 1] = '\0'; return 0; } } /* Copy the remaining string after the last org occurence, if any. */ if ((tmp = ((fmt + fmtlen) - s)) && newlen + tmp < buflen) { memcpy(buf + newlen, s, tmp); newlen += tmp; } else if (newlen + tmp >= buflen) { /* Just to return something. */ memcpy(buf + newlen, s, (buflen - 1) - newlen); buf[buflen - 1] = '\0'; return 0; } buf[newlen] = '\0'; return newlen; } Ένα παράδειγμα χρήσης θα μπορούσε να είναι το παρακάτω: > #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> size_t str_replace(const char *fmt, const char *org, const char *rep, char *buf, size_t buflen); int main(int argc, char* argv[]) { char strbuf[29]; size_t rsize; rsize = str_replace("The {i} are the best!", "{i}", "insomniacs", strbuf, sizeof (strbuf)); if (rsize) fprintf(stdout, "After replacement: %s\n", strbuf); else fprintf(stderr, "Truncated result: %s\n", strbuf); return (EXIT_SUCCESS); } Τέλος, το αποτέλεσμα ύστερα από την εκτέλεση είναι: >After replacement: The insomniacs are the best! ΥΓ. Το μέγεθος του buffer που δόθηκε στην main (29) είναι ακριβώς αυτό που χρειάζεται για να "χωρέσει" το replacement string στο destination buffer. Ευχαριστώ για τον χρόνος σας.
NewProject Δημοσ. 27 Οκτωβρίου 2010 Δημοσ. 27 Οκτωβρίου 2010 σε C++ : > void WordReplace(Word* str,Word o,Word n){ *str = str->substr(0,str->find(o)) + n + str->substr(str->find(o)+o.size()); } *το 'Word' ειναι 'std::string' αν και μαλλον δεν ειναι αυτο που ψαχνεις
Επισκέπτης Δημοσ. 27 Οκτωβρίου 2010 Δημοσ. 27 Οκτωβρίου 2010 σε C++ :αν και μαλλον δεν ειναι αυτο που ψαχνεις Αμφιβάλλω εάν μπήκες στον κόπο να διαβάσεις αυτό που έγραψα
NewProject Δημοσ. 27 Οκτωβρίου 2010 Δημοσ. 27 Οκτωβρίου 2010 Αμφιβάλλω εάν μπήκες στον κόπο να διαβάσεις αυτό που έγραψα καλα εκανες και δεν ειπες 'ειμαι σιγουρος' γιατι θε επεφτες εξω ... ναι , το διαβασα ολο και γι'αυτο εγραψα οτι δεν ειναι αυτο που ψαχνεις εσυ . Αλλα οπως και να το κανουμε , φορουμ ειναι αυτο και μπορει να φανει χρησιμο σε καποιους αλλους
MeTaXaS4 Δημοσ. 27 Οκτωβρίου 2010 Δημοσ. 27 Οκτωβρίου 2010 βασικά newproject απλώς αυτό που postares είναι μόνο για C++ o DiAvOl απλώς θέλει να φτιάξει κάτι αντίστοιχο στην C
Επισκέπτης Δημοσ. 27 Οκτωβρίου 2010 Δημοσ. 27 Οκτωβρίου 2010 Βρε παιδιά δεν θέλω να φτιάξω κάτι.. έτοιμο είναι το function! Εάν κάποιος θέλει να το ρίξει μια ματιά και να δώσει ιδέες για βελτιώσεις ή άλλες παρατηρήσεις ζήτησα.
NewProject Δημοσ. 27 Οκτωβρίου 2010 Δημοσ. 27 Οκτωβρίου 2010 μα το ξερω και το ειπα πιο πανω κιολας απλα οπως το παιδι εγραψε αυτο που εχει φτιαξει σε C , ετσι εγραψα και εγω το ανιστοιχο σε C++
Evgenios1 Δημοσ. 28 Οκτωβρίου 2010 Δημοσ. 28 Οκτωβρίου 2010 Περιεργο, η cstd δεν εχει replace ... ισως βγει στο επομενο standar. Τεσπα, αποτι βλεπω μπροεις να βαλεις memcpy αντι strncat για να αποφυγεις μερικα loops
Επισκέπτης Δημοσ. 28 Οκτωβρίου 2010 Δημοσ. 28 Οκτωβρίου 2010 Περιεργο, η cstd δεν εχει replace ... ισως βγει στο επομενο standar. Τεσπα, αποτι βλεπω μπροεις να βαλεις memcpy αντι strncat για να αποφυγεις μερικα loops Ναι ίσως η memcpy ή strncpy θα ήταν λίγο ποιο γρήγορες.
bokarinho Δημοσ. 28 Οκτωβρίου 2010 Δημοσ. 28 Οκτωβρίου 2010 Βρε παιδιά δεν θέλω να φτιάξω κάτι.. έτοιμο είναι το function! Εάν κάποιος θέλει να το ρίξει μια ματιά και να δώσει ιδέες για βελτιώσεις ή άλλες παρατηρήσεις ζήτησα. Φίλε DiAvOl εξαιρετική δουλειά. Μου άρεσε ο κώδικας σου τον δοκίμασα σίγουρα θα κάνουμε κάποιες βελτιώσεις. Την κράτησα την συναρτησούλα σου φαίνεται χρήσιμη. Μιας και πιάσαμε τα string πάρε και μία left trim από εμένα που έγραψα μόλις τώρα για ένα project που ετοιμάζω. > /* Trims a string from the left according to the input character. */ char *LTrim(char *unTrimmed, const char Ruler) { if(!unTrimmed) return NULL; if(!Ruler) return unTrimmed; else { char *p = NULL, *dupTrim = unTrimmed; /* Loop. */ do { if(!(p = strchr((char*)dupTrim, (int)Ruler)) || isalpha((int)*dupTrim)) break; /* Do the trick. */ memmove(dupTrim, p+1, strlen(p)); }while(1); /* Return the string. */ return dupTrim; } }
Επισκέπτης Δημοσ. 28 Οκτωβρίου 2010 Δημοσ. 28 Οκτωβρίου 2010 Φίλε DiAvOl εξαιρετική δουλειά. Μου άρεσε ο κώδικας σου τον δοκίμασα σίγουρα θα κάνουμε κάποιες βελτιώσεις. Την κράτησα την συναρτησούλα σου φαίνεται χρήσιμη. Μιας και πιάσαμε τα string πάρε και μία left trim από εμένα που έγραψα μόλις τώρα για ένα project που ετοιμάζω. Σε ευχαριστώ. Έχω κάνει κάποιες βελτιώσεις (αντί για strncat -> memcpy) όπως πολύ σωστά πρότεινε ο φίλος Ευγένιος!
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.