Schleife



  • hallo, ich habe folgendes Problem. Habe mir jetzt meine Fkt. ersetzen neu geschrieben, welche aber noch nicht funzt.
    diese Funktion ersetzt einen gesuchten String durch einen anderen.
    diese Funktion wird nur einmal durchlaufen, wie kann ich dort eine Schleife rum setzen, damit wirklich jeder Suchstring ersetzt wird und nicht nur der erste. Ich wollte ja mit einer Schleife arbeiten, welche prüft ob strstr NULL ergibt, komme aber auf keinen grünen zweig...

    char* ersetzen(const char* re, const char* repl, const char* in, char* buffer) {
    	char* ptr;
    	if (!re || !repl || !in || !buffer) return buffer=NULL;
    	ptr=strstr(in, re);
    	if(!ptr) {
    		strcpy(buffer, in);
    return buffer;
    }
    
    	*buffer=0;
    	if (ptr!=in) {    
    		strncpy(buffer, in, ptr-in);
    		buffer[ptr-in]=0; // damit ich strcat benuzten kann
    	}
    	strcat(buffer, repl);
    
    	ptr+=strlen(re);
    	strcat(buffer, ptr);
    
          return buffer;
    
    }
    


  • Ich versuche mal zu umschreiben wie du das machen müsstest.

    Du suchst also schon mal mit strstr das erste Vorkommen deines Suchstrings. Nun beginnt deine Schleife. Du musst erstmal abprüfen, ob der Suchstring überhaupt gefunden wurde. Wenn ja dann musst du alles aus deinem Parameter in bis zum Auftreten des Suchstrings nach buffer kopieren (machst du ja schon ;)). Danach kopierst du den zu ersetzenden String ans Ende von Buffer (machst du eigentlich auch schon) und zu guter letzt muss noch der Zeiger ptr hinter den Suchstring gesetzt werden (hast du eigentlich auch schon drin), damit er nicht immer wieder findet (-> Endlosschleife). Jetzt suchst du wieder nach dem Suchstring über strstr(), nur diesmal nicht vom Anfang von in weg sondern von ptr. Als Folge darfst du natürlich nur noch den Teil nach ptr bis zur neuen gefunden Stelle des Suchstrings ans Ende von buffer kopieren. (Da liegt wahrscheinlich bei dir der Hacken, oder??) Nach der Schleife kopierst du den Rest von in ans Ende von buffer (wie du es ja eh auch schon machst :)).

    Ich hoffe es ist ein wenig klarer.

    PS: Sinnvollere Namensgebung bei den Variablen wäre gut. Anstatt re z. B. suche oder suchstring und anstatt repl vielleicht ersetze oder ersetzstring. in ist auch ein Name mit dem man wenig anfangen kann, wenn man sich den Quellcode nicht dazu ansieht.
    Kommentare sind leider auch etwas kurz gekommen. Du und auch andere werden dir noch dankbar sein für jeden Kommentar, den du reinmachst ;).



  • Ich komme trotzdem noch nicht so richtig klar damit, wo ich die Schleife einsetzen soll.
    Ist das so in der Art korrekt?

    char* ersetzen(const char* re, const char* repl, const char* in, char* buffer) {
    
    	char *pdest;
    	pdest= strstr(in,re);
    	char* ptr;
    
    	while(pdest)
    	{
    
    		if (!re || !repl || !in || !buffer) return buffer=NULL;
    		ptr=strstr(in, re);
    		if(!ptr)  {
    			strcpy(buffer, in);
    			return buffer;
    		}
    
    		*buffer=0;
    		if ((ptr!=in) && (pdest!=0)){   
    
    			strncpy(buffer, in, ptr-in);
    			buffer[ptr-in]=0; // damit ich strcat benuzten kann
    		}
    		strcat(buffer, repl);
    
    		ptr+=strlen(re);
    		strcat(buffer, ptr);
    
    		pdest = strstr(in+1,re);
    
    	}
    	return buffer;
    
    }
    

    Funktioniert aber noch nicht... 😞



  • So stimmts auch noch nicht. Einfach die Schleife rumdum zu machen, funktioniert nicht :).

    Dein bisheriger Ablauf ist auch noch nicht geeignet für eine Schleife.

    Ich versuch es mal anhand eines Beispiels zu machen, wie es deine Funktion machen sollte:

    Text = "hallihallo"
    Suchstring = "ll"
    Ersetzstring = "pp"
    Buffer = ""

    1. Suchstring wird an Position 3 (Index 2) gefunden
    2. (Schleifenbeginn) Alles vor dem Suchstring in Text wird nach Buffer kopiert -> Buffer = "ha"
    3. Danach kommt Ersetzstring hinzu -> Buffer = "happ"
    4. Die Position wird um die Länge von Suchstring erhöht -> Pos = 5
    5. Die Position wird in alter Position gemerkt
    6. Der Suchstring wird nun ab Position gesucht und an Position 8 in Text gefunden
    7. Alles zwischen alter Position und Position wird an Buffer drangehängt -> Buffer = "happiha"
    8. siehe 3. -> Buffer = "happihapp"
    9. siehe 4. -> Pos = 10
    10. siehe 5.
    11. Wieder wird gesucht nach dem Suchstring, diesmal wird er aber nicht gefunden (Schleifenende)
    12. Der Rest von Text wird an Buffer angehängt -> Buffer = "happihappo"



  • @AJ
    ich kann deinen logischen aufbau vollkommmen nachvollziehen, komme aber leider mit den ganzen Stringfunktionen noch nicht so klar, und daher ist die Umsetzung deiner "Anleitung" auch gar nicht so einfach für mich (bin ja auch noch nícht solange im Geschäft).
    Ich werde aber noch mal versuchen das hinzubekommen. Danke



  • @AJ
    Kannst du mir evtl. noch einen Ansatz programmieren? So bis zu deinem 3. oder 4. Punkt? Weiß irgendwie trotz Anleitung nicht, wie ich richtig anfange (zu blöd). Ich hoffe, wenn ich nen Ansatz sehe, dann gehts.
    Das mit dem 1. ist OK: (char* prt = strstr(in,re))
    Aber jetzt gehts schon los: Wie kriege alles vor dem Suchstring in buffer???
    evtl. so??? strncpy(buffer,in,petr-in) ?????? Keine Ahnung... 😡



  • Ok ich mach dir mal den Anfang:

    ...
    char *pos, *altpos;
    int len;
    ... //Deine vorherigen Abprüfungen
    
    //Suche Suchstring in Text
    pos = strstr(in, re);
    //Speichere alte Position (hier Anfang)
    altpos = in;
    //Buffer initialisieren
    *buffer = 0;
    
    //Solange der Suchstring in Text gefunden wird
    while(pos)
    {
       //Merke Länge von buffer
       len = strlen(buffer);
       //Kopiere von alter Position bis Position des Suchstrings nach buffer
       strncat(buffer, altpos, pos-altpos);
       //Stringendezeichen setzen
       buffer[len+pos-altpos] = 0;
    
       //Hier muss noch ein wenig was gemacht werden ;)
       ...
    
       //Position nach Suchstring in Text ermitteln
       altpos = pos + strlen(re);
       //Suche nach weiteren Suchstring in Text hinter letzten gefundenen Suchstring
       pos = strstr(altpos, re);
    }
    //Hänge Rest von Text an Buffer an
    strcat(buffer, altpos);
    ...
    


  • Ich seh gerade das er hier auch gepostet hab. damit das nicht in 100 verschiedenen threads diskutiert wird und jeder 30 mal das gleiche sagt.(Ich glaub in unserem Forum sind auch schon 3 threads zu diesem thema offen). aktuell gehts gerade hier weiter fals noch jemand was dazu beisteuern will
    http://www.fun-soft.de/showtopic.php?threadid=6950&post_start=10&time=1082990889



  • @ Windalf

    Wie kann ich den bisherigen Code von dir noch ändern, damit auch ein größerer String eingefügt bzw. ersetzt werden kann???

    P.S. Sorry, aber dies ist dann die letzte Frage zu dem Thema.
    ⚠
    Ich habe schon versucht das inp-array zu vergrößern, was aber auch nicht funktionierte.
    Ich meine wenn ich den String durch einen kleineren ersetze funktioniert es astrein. Aber es muss nicht zwangsweise ein kleinerer String ersetzt werden und deshalb wollte ich mir die Mgl. offen halten, auch diesen durch einen größeren zu ersetzen.

    P.S. Bitte um letzte Hilfe



  • Sorry, hier natürlich noch der bisherige code:

    int ersetzen(char *such, char *neu, char *inp){ 
    int flag,rv=0;
    char *p,*q,*r,*tmp;
        tmp=new char[strlen(inp)+1];
        for(p=inp;*p;++p){
            flag=1;    
            for(q=such,r=p;*q&&*r&&flag;++q,++r)if(*q-*r)flag=0;
    
            if(flag){
                for(q=tmp;*r;++q,++r)*q=*r;
                *q='\0';
                for(q=neu,r=p;*q;++q,++r)*r=*q;
                for(q=tmp;*q;++r,++q)*r=*q;
                *r='\0';
                ++rv;
            }        
        }
    
        delete [] tmp;
    
        return rv;
    }
    


  • new
    delete

    Somit hat das nichts mehr mit ANSI-C zu tun. Ab damit nach C++. Außerdem ist der Quellcode unübersichtlich und nicht mal kommentiert *mecker*(hat aber seine Gründe!).



  • @AJ
    also wenn dich das new und delete so stört mach ein malloc draus.
    als ob das jetzt ein wirkliches problem ist.
    heute wohl ne nörgeltablette gefuttert 😃

    @evil411_unlogged
    da einfach nur inp überschrieben wird, musst du inp halt nur entsprechend gross allokieren nicht mehr und nicht weniger.
    und wie gesagt wenn du rekursive ersetzungen vermeiden willst solltest du nach einer ersetzung auf p nach ein strlen(neu) draufaddieren.

    so damit es hier im forum verweilen kann ein kleiner patch

    int ersetzen(char *such, char *neu, char *inp){ 
    int flag,x=strlen(neu),rv=0;
    char *p,*q,*r,*tmp;
        tmp=(char*)malloc(sizeof(char)*(strlen(inp)+1));
        for(p=inp;*p;++p){
            flag=1;    
            for(q=such,r=p;*q&&*r&&flag;++q,++r)if(*q-*r)flag=0;
    
            if(flag){
                for(q=tmp;*q++=*r++;);
                for(q=neu,r=p;*r++=*q++;);
                for(q=tmp,--r;*r++=*q++;);
                p+=x;
                ++rv;
            }        
        }
    
        free(tmp);
    
        return rv;
    }
    

    ach so und an sonsten zeig doch mal wie du ein inp-array definiert hast. bzw. wie du versucht hast es zu vergrössern



  • Windalf schrieb:

    heute wohl ne nörgeltablette gefuttert 😃

    Anscheinend...
    Mich stört der ganze Umstand einfach. Da wird an verschiedenen Stellen nachgefragt und dann werden die Lösungen wild durcheinander geschustert *kopfschüttel*.
    Außerdem ist dieser Quellcode mehr als misserabel zu lesen und das stört mich noch viel mehr. Warum hat der Ersteller nicht gleich alles in eine Zeile gepresst?? 🙄

    Ich hab auf jeden Fall keine Lust mehr einmal an der Version rumzudoktern, dann an einer ganz anderen Version, weil jemand anderes irgendwo wieder eine andere Lösung hat und auf einmal diese übernommen wird usw.



  • Ja, das mit dem new und dem delete ist schon in Ordnung.
    Das ist ja nicht das Hauptproblem, sondern den String irgendwie ersetzen...
    den inp-String bzw. das inp-array (char inp[MAX_LEN] --> MAX_LEN =100000) wird mit fgets aus einer Datei eingelesen. Wie mache ich denn nun das mit dem Array allokieren?. Wie groß muss denn das Array sein???



  • **@AJ & Windalf
    **

    Es tut mir wirklich leid, wenn ich euch solche Schwierigkeiten bereite. Ich atme nun mal noch nichts so lange die C/C++-Luft ein, was heißen soll, dass ich ziemlicher Anfänger bin. 😞
    Da ich mich zwischen verschiedenen Lösungsvorschlägen nicht entscheiden konnte (PS: bin froh, wenn überhaupt eins funzt) habe ich ab und zu gewechselt. Weiterhin wusste ich bis gestern auch nicht, dass diese beiden Foren so eng zusammenarbeiten. 😞
    Auf jeden Fall tut es mir leid, dass ich immerzu einen neuen Thread angelegt, bzw. immer die selbe Frage zu unterschiedlichen Codes gestellt habe.
    😞
    Ich weiß es ist für euch nicht einfach. Auf jeden Fall wird so etwas nicht mehr vorkommen und ich bedanke mich trotzdem für eure Hilfe.
    Also Danke und Sorry, bis zum nächsten "einmaligen" Thread 🤡



  • @AJ
    öhm, der Ersteller war ich 😉
    warum ichs nicht in eine zeile gepresst habe. weil ichs dann nicht mehr lesen kann, so wie es jetzt ist komm ich gut mit klar.

    mal davon abgesehen das die variablennamen nicht sprechend sind, was ist an dem code sonst auszusetzen?

    @evil411
    angenommen du ersetzt ein wort aus 3 buchstaben gegen eines aus 5, dann ist dein text am ende anzahl der ersetzungen*2 länger als der vorherige.
    zum testen könntest du jetzt einfach mal doppelte bufferlänge die du für deinen text brauchst nehmen. das wird in den meisten fällen reichen. an sonsten müsstest du in der funktion ggf speicher mit realloc nachallokieren, falls der grösse des buffers nicht ausreichen sollte.

    so falls ich in meiner funktion kein fehler gemacht habe (kann man ja auch nicht ausschliessen und getestet hab ichs auch nicht gross) musst du das einfach nur in der art benutzen.

    int laenge_text=100000;
    char *text = malloc(sizeof(char)*2*laenge_text);
    sprintf(text,"%s","tralalalalala 1234 abc usw....");//oder was auch immer du da in den string reinballern willst
    printf("%s\n",text);
    ersetzen("1234","xyz",text); 
    printf("%s\n",text);
    


  • Windalf schrieb:

    mal davon abgesehen das die variablennamen nicht sprechend sind, was ist an dem code sonst auszusetzen?

    Du hast keinerlei Kommentare drin, was generell schlecht ist.
    Und ich hab deswegen gefragt, warum du nicht gleich alles in eine Zeile schreibst, weil du for() if() und eine Anweisung direkt hintereinander hast. Was zumindest ich persönlich als sehr unübersichtlich emfinde. Es wirkt einfach zusammengepresst und unübersichtlich.

    Etwas mit dem ich auch nicht klarkomme, ist die Schreibweise der { am Ende einer Zeile, also z. B. direkt hinter if. Ich hab da immer das Problem, dass ich diese Klammer schlichtweg überlese und mich dann über eine } weiter unten wundere. Aber das ist wohl eher ein Problem von mir ;).

    Zum Problem mit inp und des reservierten Speichers:
    Man könnte inp auch als Zeiger auf einen Zeiger übergeben (**) und in der Funktion mir realloc() bei Bedarf vergrößern. Die aktuelle Größe von inp wäre dann natürlich auch nützlich ;).



  • Wie könnte ich das mit dem realloc noch einbauen? Wenn ich die Größe verdopple, funzt es leider nicht... 😉



  • int ersetzen(const char *such, const char *neu, char **inp, int *inp_len)
    {
    ...
       //Wenn die Anzahl der Zeichen, die in inp gespeichert werden sollen, mehr sind
       //als in inp passen
       if(... >= *inp_len)
       {
          //um 1024 Byte vergrößern (kann auch eine andere Größe sein)
          *inp_len += 1024; 
          //größeren Speicherplatz reservieren
          *inp = realloc(*inp, *inp_len); 
          //Prüfung ob Reservierung geklappt hat
          if(!*inp)
          {
             //Kein Speicher mehr verfügbar, also raus!
             //(davor evtl. noch Sachen machen, die beim Beenden wichtig sind, z. B. free())
             exit(1); 
          }
       }
    ...
    }
    


  • Bei realloc bekomme ich immer einen Fehler von wegen:

    Konvertierung des Parameters 1 von 'char' in 'void *' nicht moeglich
    

    ... obwohl mein 1.Parameter *inp ist. Müsste doch eigentlich hinhauen oder??


Anmelden zum Antworten