Bestimmte Zeichen aus String entfernen? GCC

OP #5301558
Lesenswert?

Nabend,

Wie oben erwähnt würde Ich gerne aus einem String bestimmte Zeichen raus 
löschen und die Zeichen die danach kommen, hinten an den String wieder 
anfügen, so daß dort keine Leerzeichen entstehen.

Test String: Gutxxen Axxxbend
Ziel String: Guten Abend

Was macht man jetzt am besten? Man könnte es ja einfach umkopieren mit 
ein paar abfragen in ein anderes Array..

Gibt es noch eine gute Alternative?
Gast #5301606
Lesenswert?

1
#include <iostream>
2
#include <string>
3
#include <algorithm>
4
#include <iterator>
5

6
int main () {
7
  std::string str ("Gutxxen Axxxbend");
8
  std::cout << "Vorher: " << str << std::endl;
9
  str.erase (std::remove (begin (str), end (str), 'x'), end (str));
10
  std::cout << "Nachher: " << str << std::endl;
11
}
Ausgabe:
1
Vorher: Gutxxen Axxxbend
2
Nachher: Guten Abend
OP #5301607
Lesenswert?

Dr. Sommer schrieb:
> #include <iostream>
> #include <string>
> #include <algorithm>
> #include <iterator>
>
> int main () {
>   std::string str ("Gutxxen Axxxbend");
>   std::cout << "Vorher: " << str << std::endl;
>   str.erase (std::remove (begin (str), end (str), 'x'), end (str));
>   std::cout << "Nachher: " << str << std::endl;
> }
> Ausgabe:Vorher: Gutxxen Axxxbend
> Nachher: Guten Abend

Das ist C++
#5301624
Lesenswert?

Du meine Güte, das ist doch nun wirklich keine Raketenwissenschaft. 
Offensichtlich mußt du Zeichen für Zeichen durch den String gehen und 
unerwünschte Zeichen überspringen. Du kannst noch überlegen, ob du das 
Ergebnis in einen neuen String kopierst oder gleich den alten String 
überschreibst.
OP #5301630
Lesenswert?

Axel S. schrieb:
> Du meine Güte, das ist doch nun wirklich keine Raketenwissenschaft.
> Offensichtlich mußt du Zeichen für Zeichen durch den String gehen und
> unerwünschte Zeichen überspringen. Du kannst noch überlegen, ob du das
> Ergebnis in einen neuen String kopierst oder gleich den alten String
> überschreibst.

Ich will den alten String benutzen. Möchte ihn aber nicht überschreiben.

Die Zeichen sollen gelöscht werden die unerwünscht sind und jeweils soll 
kein Leerzeichen dazwischen stehen, also sollten die Zeichen die danach 
kommen nach links verschoben werden.
Gast #5301635
Lesenswert?

Jan H. schrieb:
> Dr. Sommer schrieb:
>> #include <iostream>
>> #include <string>
>> #include <algorithm>
>> #include <iterator>
>>
>> int main () {
>>   std::string str ("Gutxxen Axxxbend");
>>   std::cout << "Vorher: " << str << std::endl;
>>   str.erase (std::remove (begin (str), end (str), 'x'), end (str));
>>   std::cout << "Nachher: " << str << std::endl;
>> }
>> Ausgabe:Vorher: Gutxxen Axxxbend
>> Nachher: Guten Abend

OMG!

schon mal was von 'regular expressions' gehört?
Moderator Persönliche Seite #5301641
Lesenswert?

1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4

5
// 1. Loeschen durch Kopieren:
6
void remove_1 (char * target, const char * str, int maxlen)
7
{
8
    while (*str && maxlen)
9
    {
10
        if (*str != 'x')
11
        {
12
            *target++ = *str;
13
            maxlen--;
14
        }
15
        str++;
16
    }
17
    *target = '\0';
18
}
19

20
// 2. Loeschen direkt im String:
21
void remove_2 (char * str)
22
{
23
    char * p;
24

25
    while (*str)
26
    {
27
        while (*str == 'x')
28
        {
29
            for (p = str; *p; p++)
30
            {
31
                *p = *(p + 1);
32
            }
33
        }
34
        str++;
35
    }
36
}
37

38
int main ()
39
{
40
    char s[64];
41
    char t[64];
42

43
    strcpy (s, "Gutenxxx Tagxxx");
44
    remove_1 (t, s, 63);
45
    printf ("%s -> %s\n", s, t);
46

47
    remove_2 (s);
48
    printf ("%s\n", s);
49
    return 0;
50
}
1
$ cc rem.c -o rem && ./rem
2
Gutenxxx Tagxxx -> Guten Tag
3
Guten Tag
Gast #5301654
Lesenswert?

Drei Schleifen ineinander?! Das geht einfacher:
1
#include <stdio.h>
2
#include <stddef.h>
3

4
size_t remove_2 (char* str, size_t n) {
5
  size_t i, j;
6
  for (i = 0, j = 0; j < n; ++j)
7
    if (str[j] != 'x')
8
      str[i++] = str[j];
9
  return i;
10
}
11

12
int main () {
13
  char str [] = "Gutenxxx Tagxxx";
14
  printf ("Vorher : %s\n", str);
15
  str [remove_2 (str, sizeof (str))] = 0;
16
  printf ("Nachher: %s\n", str);
17
}
Moderator Persönliche Seite #5301656
Lesenswert?

Jan H. schrieb:
> Das die x entfernt werden und der Text danach jeweils um eins verschoben
> nach links rückt? Geht damit nicht?

Der Text wird doch nach links verschoben. Probiers einfach aus oder gehe 
das Programm mit Bleistift und Papier schrittweise durch.

Ein wenig den eigenen Grips anstrengen muss man beim Programmieren (oder 
beim Programm-Lesen) schon. Wenn Dich das jetzt überfordert, schnapp dir 
ein C-Buch und arbeite es systematisch durch. Pointer sind nicht das 
erste, was man bei C lernen sollte.
#5301718
Lesenswert?

Jan H. schrieb:
> Ich will den alten String benutzen. Möchte ihn aber nicht überschreiben.
>
> Die Zeichen sollen gelöscht werden die unerwünscht sind

Das widerspricht sich. Wenn du Zeichen im String löschst, dann 
überschreibst du ihn doch?

@Frank M. & Co.

Helfersyndrom? Das ist ein wirklich triviales Problem. Wenn er das nicht 
selber hinbekommt, dann bekommt er nie irgendwas hin.
#5302229
Lesenswert?

Man muss das auch in C nicht zu Fuß machen:
1
#include <string.h>
2
#include <stdio.h>
3

4
void removeChars (char * input, const char *unwanted, char * output)
5
{
6
  char * substring = strtok(input, unwanted);
7

8
  *output = 0;
9

10
  while(substring != NULL) {
11
    strcat (output, substring);
12
    substring = strtok(NULL, unwanted);
13
  }
14
}
15

16

17
int main ()
18
{
19
  char output[100];
20
  char input[100];
21

22
  strcpy (input, "Gutxxen Axxxbend"); 
23

24
  removeChars (input, "x", output);
25
  puts (output);
26
  
27
  return 0;
28
}

Die Funktion erledigt auch gleich das entfernen mehrerer Zeichen. Kannst 
also xy und z in einem Rutsch aus dem String tilgen.
OP #5302397
Lesenswert?

Nils P. schrieb:
> void removeChars (char * input, const char *unwanted, char * output)
> {
>   char * substring = strtok(input, unwanted);
>
>   *output = 0;
>
>   while(substring != NULL) {
>     strcat (output, substring);
>     substring = strtok(NULL, unwanted);
>   }
> }

Die Funktion ist auch gut. Funktioniert einwandfrei.
Habe mich wahrscheinlich ein wenig undeutlich ausgedrückt.

Den String, den Ich absuchen möchte, soll bearbetiet werden. Das heißt 
die Zeichen die dort in dem String vorkommen, die gesucht werden sollen 
daraus entfernt werden.

Die Funktion von Frank M. erfüllt genau diesen Zweck. Ich werde mir 
diese jetzt mal genauer anschauen, damit Ich es verstehe. Vielen Dank 
für die Hilfe.
#5302442
Lesenswert?

Jan H. schrieb:
> Ich will den alten String benutzen. Möchte ihn aber nicht überschreiben.

Ein String braucht einen Puffer, also ein Stück Speicher, und einen 
Pointer.

Wenn du den alten String erhalten willst, musst du ihn in einen neuen 
Puffer kopieren. Wenn du den alten Puffer für den neuen String benutzen 
willst, geht das nicht ohne ihn zu überschreiben.


Hier eine Funktion zum kopieren ohne die Zeichen im String without:
1
char * stpcpywithout(char *t,const char *s,const char * without){
2

3
while (*s){
4
  if (strchr(without,*s)==NULL)*t++=*s;
5
  s++;
6
  }
7
*t=0;
8
return t;
9
}

Zurückgegeben wird ein Zeiger auf die Null am Stringende, er kann 
benutzt werden für das Anhängen von weiteren Strings oder Zeichen.

Du kannst die Kopierfunktion auch mit demselben Puffer verwenden, da der 
Lesezeiger s entweder identisch mit dem Schreibzeiger t ist oder ihm 
vorauseilt:
1
stpcpywithout( str, str,"x");
#5302481
Lesenswert?

Das ist nur auf den ersten Blick eine einfache Sache.

Wird aus: "Gutxxen Axxxbend"
"xx" und "xxx" entfernt, so soll trotzdem NICHT aus:
"Text" -> "Tet" werden.

Auch ist "Axbend" nicht besonders schön, auch wenn vorher "Axxxxbend"
da stand.

Zugegeben, "xx" ist in der deutschen Sprache wohl nicht allzu häufig, 
aber einfach über die Anzahl an Zeichen zu filtern, wird auch in die 
Hose gehen.

Ob das überhaupt - ohne Wörterbuch - machbar ist, weiß ich nicht. Aber 
allzu viel Info hat der TO ja auch nicht rübergebracht.
Moderator Persönliche Seite #5302506
Lesenswert?

Sebastian S. schrieb:
> Wird aus: "Gutxxen Axxxbend"
> "xx" und "xxx" entfernt, so soll trotzdem NICHT aus:
> "Text" -> "Tet" werden.

Ich nehme doch stark an, dass der TO das 'x' nur als ein exemplarisches 
Beispiel genommen hat, welches mit der tatsächlichen Aufgabe in der 
Realität gar nichts zu tun hat. Von daher sind Deine Folgerungen reine 
Spekulation.
Gast #5302510
Lesenswert?

Nils P. schrieb:
> void removeChars (char * input, const char *unwanted, char * output)
> {
>   char * substring = strtok(input, unwanted);
>
>   *output = 0;
>
>   while(substring != NULL) {
>     strcat (output, substring);
>     substring = strtok(NULL, unwanted);
>   }
> }

Diese Funktion ist ohne Not O(n²) statt O(n).

Ist bei kurzen Texten sicher egal, und mag elegant zu tippen sein, aber 
grade bei so Anfänger-Fragen sollte man dazuschreiben, dass diese 
Funktion um Welten schlechter ist als die anderen Vorschläge.

Sonst passiert sowas:

Jan H. schrieb:
> Die Funktion ist auch gut.

Nein. Sie ist eine ganz Kategorie schlechter als die anderen.
#5302716
Lesenswert?

@Frank
>Ich nehme doch stark an, dass der TO das 'x' nur als ein exemplarisches
>Beispiel genommen hat, welches mit der tatsächlichen Aufgabe in der
>Realität gar nichts zu tun hat. Von daher sind Deine Folgerungen reine
>Spekulation.

Dann erst recht!
So kommen die Buchstaben "s" oder "f" bis zu 3-mal in einem Wort vor, 
ohne das der Herr Duden darüber meckert.

Aber worauf ich hinaus will ist: Es ist, ohne den gesamten Text im Auge 
zu behalten gefährlich, irgend welche Buchstabenkombinationen - ohne 
Quittung - zu ersetzen.
OP #5303078
Lesenswert?

Leider kann Ich hier nicht so viele "Zitatzeilen" einfügen.

Ich spreche das Beispiel von Frank M. (remove_2) an...

Jetzt muss Ich doch eine Frage los werden.. Was genau macht der Zeiger 
"*p" wenn er nicht zurück gegeben wird? Und wieso wird "*str" richtig 
zurückgegeben wenn dieser gar nicht bearbeitet wird?!
#5303136
Lesenswert?

Wenn alle dürfen, dann ich auch. Die Funktion kopiert den String auf 
sich selbst und überspringt dabei alle Vorkommen des unerwünschten 
Zeichens. Da der Zielstring nicht länger sein kann als das Original, 
geht das immer.

Ich habe versucht, es sowohl kompakt als auch lesbar zu formulieren.
1
void remove_inplace(char *str, char unwanted)
2
{
3
  char *dst= str;
4
  char c;
5
  while ((c= *str++))
6
    if (c != unwanted)
7
      *dst++= c;
8

9
  *dst= 0;
10
}

so könnte man das verwenden:
1
int main(void)
2
{
3
  char s[]= "Halxxlo Wexlt!";
4
  printf("vorher:  '%s'\n", s);
5
  remove_inplace(s, 'x');
6
  printf("nachher: '%s'\n", s);
7
}
Moderator Persönliche Seite #5303138
Lesenswert?

Jan H. schrieb:
> Jetzt muss Ich doch eine Frage los werden.. Was genau macht der Zeiger
> "*p" wenn er nicht zurück gegeben wird? Und wieso wird "*str" richtig
> zurückgegeben wenn dieser gar nicht bearbeitet wird?!

Du meinst:
1
            for (p = str; *p; p++)
2
            {
3
                *p = *(p + 1);
4
            }

Der Pointer p läuft von der Stelle los, an der str gerade steht und 
"zieht" die Zeichen, die rechts davon stehen, um eine Stelle nach links. 
Die for-Schleife wird beendet, wenn der String zu Ende ist.

Beispiel: "abcxdef" im RAM untereinander geschrieben:
1
   a
2
   b
3
   c
4
   x  <--- da steht im Moment str und damit auch p wgen for (p = str;...)
5
   d
6
   e
7
   f
8
   \0 Hier ist der String zu Ende

Wegen *p = *(p + 1) wird nun das d an die Stelle von x kopiert, e an die 
alte Stelle von d, f an die alte Stelle von e. Als letztes wird noch der 
String-Terminator \0 nach links kopiert. Nach Durchlauf der for-Schleife 
steht dann im RAM:
1
   a
2
   b
3
   c
4
   d  <--- da steht immer noch str
5
   e
6
   f
7
   \0 Nun ist der String-Terminator eine Stelle weiter links
8
   \0 Der alte String-Terminator, hier steht jetzt p

Damit wurde das x eliminiert und der Teilstring "def" inkl. Terminator 
ist um eine Stelle nach links gewandert.

Deine Frage zeigt, dass Du noch waschechter Anfänger bist. Ich gebe Dir 
nochmal den Tipp, ein C-Buch systematisch durchzuarbeiten. Man kann 
keine Programmiersprache in einem Forum lernen. Außerdem sind Pointer 
bei einem C-Kurs erst dran, wenn man die Basis bereits gelernt hat.
Gast #5304600
Lesenswert?

Nur mal die Auflösung aus 
Beitrag "Re: Bestimmte Zeichen aus String entfernen? GCC":
1
char * strcpy(char *s1, const char *s2)
2
{
3
void *s = s1;
4

5
  while(*s2) *s1++ = *s2++;
6
  *s1 = (char)0;
7
  return s;
8
}
Anpassungen:
1) es braucht keinen Rückgabewert
2) es braucht nur einen Pointer (s1 = s2)
3) es braucht ein zu entfernendes Zeichen (int c)
4) umdrehen auf do while, damit keine Sonderbehandlung für abschließende 
0
5) Sicherstellen, dass c==0 nichts schlimmes macht (was immer auch dann 
passieren sollte)
1
void strcpy_masked(char *s, int c)
2
{
3
const char *s_read = s;
4

5
    do if(*s_read!=c || c==0) *s++ = *s_read; while(*s_read++);
6
}
und mit ein wenig mehr klammern und ein flg, das nicht unnötig kopiert 
wird (wobei diese Version meist nicht!! schneller ist):
1
void strcpy_masked(char *s, int c)
2
{
3
const char *s_read = s;
4
int copy=0;
5

6
    do
7
    {
8
        if(*s_read==c && c!=0) 
9
        {
10
            copy = 1;
11
        }
12
        else if(copy)
13
        {
14
            *s++ = *s_read; 
15
        }
16
        else
17
        {
18
             s++;
19
        }
20
    }while(*s_read++);
21
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren