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

[C] String replacement function - σχόλια/παρατηρήσεις


Επισκέπτης

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

Δημοσ.

Καλησπέρα,

 

Έχω γράψει ένα 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.

 

Ευχαριστώ για τον χρόνος σας.

Δημοσ.

σε 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'

αν και μαλλον δεν ειναι αυτο που ψαχνεις

Δημοσ.
σε C++ :

αν και μαλλον δεν ειναι αυτο που ψαχνεις

 

Αμφιβάλλω εάν μπήκες στον κόπο να διαβάσεις αυτό που έγραψα :)

Δημοσ.
Αμφιβάλλω εάν μπήκες στον κόπο να διαβάσεις αυτό που έγραψα :)

 

καλα εκανες και δεν ειπες 'ειμαι σιγουρος' γιατι θε επεφτες εξω ... ναι , το διαβασα ολο και γι'αυτο εγραψα οτι δεν ειναι αυτο που ψαχνεις εσυ . Αλλα οπως και να το κανουμε , φορουμ ειναι αυτο και μπορει να φανει χρησιμο σε καποιους αλλους

Δημοσ.

βασικά newproject απλώς αυτό που postares είναι μόνο για C++ o DiAvOl απλώς θέλει να φτιάξει κάτι αντίστοιχο στην C

Δημοσ.

Βρε παιδιά δεν θέλω να φτιάξω κάτι.. έτοιμο είναι το function!

 

Εάν κάποιος θέλει να το ρίξει μια ματιά και να δώσει ιδέες για βελτιώσεις ή άλλες παρατηρήσεις ζήτησα.

Δημοσ.

μα το ξερω και το ειπα πιο πανω κιολας :fear:

απλα οπως το παιδι εγραψε αυτο που εχει φτιαξει σε C , ετσι εγραψα και εγω το ανιστοιχο σε C++ :fear:

Δημοσ.

Περιεργο, η cstd δεν εχει replace :shock: ... ισως βγει στο επομενο standar.

 

Τεσπα, αποτι βλεπω μπροεις να βαλεις memcpy αντι strncat για να αποφυγεις μερικα loops

Δημοσ.
Περιεργο, η cstd δεν εχει replace :shock: ... ισως βγει στο επομενο standar.

 

Τεσπα, αποτι βλεπω μπροεις να βαλεις memcpy αντι strncat για να αποφυγεις μερικα loops

 

Ναι ίσως η memcpy ή strncpy θα ήταν λίγο ποιο γρήγορες.

Δημοσ.
Βρε παιδιά δεν θέλω να φτιάξω κάτι.. έτοιμο είναι το 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;
}
}

Δημοσ.
Φίλε DiAvOl εξαιρετική δουλειά. Μου άρεσε ο κώδικας σου τον δοκίμασα σίγουρα θα κάνουμε κάποιες βελτιώσεις. Την κράτησα την συναρτησούλα σου φαίνεται χρήσιμη. Μιας και πιάσαμε τα string πάρε και μία left trim από εμένα που έγραψα μόλις τώρα για ένα project που ετοιμάζω.

 

Σε ευχαριστώ. Έχω κάνει κάποιες βελτιώσεις (αντί για strncat -> memcpy) όπως πολύ σωστά πρότεινε ο φίλος Ευγένιος!

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...