Wie kann man mehrere Leerzeichen durch eins ersetzen in c?

... komplette Frage anzeigen

2 Antworten

Also wenn du eine naive Lösung ohne Zeiger suchst, vielleicht so:

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

void zipws(char *s) {
char c;

size_t from = 0;
size_t to = 0;

for (int ws, last = 0; (c = s[from++]); last = ws) {
ws = isspace(c);

if (!ws || !last) {
s[to++] = ws ? ' ' : c;
}
}

s[to] = '\\0';
}


int main(void) {
char s[] = "foo bar baz\\tqux\\t \\r\\nquuux";
printf("before: <%s>\\n", s);

zipws(s);
printf("after: <%s>\\n", s);

return EXIT_SUCCESS;
}

Das ersetzt alle Whitespace-Folgen (also ' ', '\\t', '\\r', '\\n', usw.; auch gemischt) durch ein einziges normales Leerzeichen, sodass obiger Test folgendes ausgibt:

before: <foo bar  baz        qux      
quuux>
after: <foo bar baz qux quuux>

Allerdings gefällt mir die Lösung persönlich aus verschiedenen Gründen überhaupt nicht, und ich würde auf jeden Fall Zeiger bevorzugen:

void zipws(char *s) {
char c, *p = s;

for (int ws, last = 0; (c = *s++); last = ws) {
if (!(ws = isspace(c)) || !last) {
*p++ = ws ? ' ' : c;
}
}

*p = '\\0';
}

Das ist zwar immer noch lange nicht perfekt, aber ich habe jetzt keine Lust Kleinigkeiten durch zu kauen. Da du aber um eine Lösung ohne Zeiger gebeten hast, nehme ich im Hauptbeispiel ganz oben am Anfang Array-Indizes zur Hilfe. :)

Außerdem musst du immer abwägen, ob du eine "clevere" Lösung bevorzugst, oder lieber etwas "Ordentliches" haben willst (im Sinne von Wartbarkeit und Verständlichkeit).

Beide Beispiele aus meiner Antwort erachte ich nicht gerade als schick, habe jetzt um 03:00 Uhr morgens aber auch nicht die Muße, mich näher damit beschäftigen zu wollen. Ich habe es nicht mal getestet ... sollte aber eigentlich in dieser Form problemlos kompilieren. ><

Gute Nacht! :)

Antwort bewerten Vielen Dank für Deine Bewertung
Kommentar von ralphdieter
20.02.2016, 11:39

Ich habe es nicht mal getestet ... sollte aber eigentlich in dieser Form problemlos kompilieren

Ganz ohne Syntax-Highlightning und ohne Autokorrektur??? Du bist ganz schön arrogant — und ich dachte immer, ich wär der einzige :-)

Trotzdem etwas Kritik:

  • Du mischst in der for-Schleife Äpfel (ws, last) und Birnen (c, s). Es hat ein Weilchen gedauert, bis ich das verstanden habe. Ich habe die Erfahrung gemacht, dass das nicht nur den Leser, sondern auch den Compiler verwirren kann; der optimiert dann nur noch halbherzig.
  • Ich glaube, dass Dein zipws() alle Leerzeichen am String-Ende ersatzlos löscht (ganz sicher bin ich mir aber nicht).
  • Du hast die Aufgabe von "Leerzeichen" auf "Whitespace" erweitert. Kann man machen, aber ich hasse es, wenn mir jemand ungefragt meine Tabulatoren und Zeilentrenner weglöscht — sei froh, dass Du nicht mein Kollege bist :-P
1
Kommentar von TeeTier
20.02.2016, 23:35

An den Fragensteller:

Ich denke, die letzte Version aus ralphdieter's Antwort ist die Schönste. Wie bereits erwähnt, muss man (fast) immer abwägen zwischen effizient und elegant, und wie du an unserer Diskussion gesehen hast, gibt es selbst bei so einer einfachen Aufgabe noch massig viel Optimierungspotential.

Um zu viele Zeiger-Dereferenzierungen zu vermeiden, könnte man noch wesentlich mehr mit "register" Variablen arbeiten, aber erstens bist du vermutlich noch nicht so weit, und zweitens ist es sicherlich nicht das, was dein Lehrer sehen will.

Auf jeden Fall hast du hier schon mal Folgendes gelernt:

- Niemals eigenständig die Anforderungen erweitern (z. B. aus "Leerzeichen" einfach "White Space" machen)

- Alle drei Teile im Kopf von for-Schleifen konsistent halten

- Dir einen einheitlichen Stil der Codeformatierung angewöhnen

- Für Optimierungen ist später Zeit; Hauptsache dein Code ist erst mal korrekt lauffähig und leicht verständlich

- Wenn du irgendwann mal fortgeschritten bist, kannst du dir mit einem Disassembler angucken, ob der Compiler deinen Code korrekt übersetzt hat

- Der Input von anderen Programmierern ist bei Veröffentlichung von eigenem Code sehr wertvoll, und durch ein paar kritische Sätze Dritter in einer Diskussion lernt man oft mehr, als beim Lesen einiger Kapitel Theorie

Also dann ... wenn ich du wäre, würde ich die letzte Lösung von ralphdieter wählen. Die benutzt zwar strlen(), ist aber sehr schön schlank.

Viel Erfolg damit! :)

0

Etwa so:

#include <string.h>

void zipspace ( char * s )
{
 while ((s=strstr(s, "  ")))
  for (char *t=s; (t[0]=t[1]); ++t)
;
}

Die innere for-Schleife macht eigentlich nur ein strcpy(s, s+1). Letzteres hat leider wegen der Überlappung undefiniertes Verhalten.

Antwort bewerten Vielen Dank für Deine Bewertung
Kommentar von BahaZahedah
19.02.2016, 19:37

danke sehr ... kann man aber ohne zeiger machen ?!

1

Was möchtest Du wissen?