Code-Schnipsel
Moderatoren: broesel, Martin Conrad, PatrickThema: trim()
Hallo,
habe gestern eine trim()-Funktion ähnlich der aus PHP gebaut. Vielleicht kann das jemand gebrauchen oder hat Verbesserungsvorschläge:
trim() entfernt also führende und endende Whitespaces.
Gruss,
Philip
habe gestern eine trim()-Funktion ähnlich der aus PHP gebaut. Vielleicht kann das jemand gebrauchen oder hat Verbesserungsvorschläge:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* whitespaces are space, tab, newline, carriage return, */
/* vertical tab and '\0' */
#define WHITESPACES " \t\n\r\x0B\0"
static int string_first_nonwhite(char *s)
{
int i = 0;
while(s[i] != '\0') {
if(strchr(WHITESPACES, s[i]) == NULL)
break;
else i++;
}
return(i);
}
static int string_last_nonwhite(char *s)
{
int len, i = 0;
len = strlen(s) - 1;
while(i < len) {
if(strchr(WHITESPACES, s[len - i]) == NULL)
break;
else i++;
}
return(len - i);
}
void string_trim(char *s)
{
int first, last;
if(s == NULL)
return;
first = string_first_nonwhite(s);
last = string_last_nonwhite(s);
if(last == 0) {
s[0] = '\0';
} else {
s[last + 1] = '\0';
memmove(s, s + first, strlen(s) - first + 1);
}
}
trim() entfernt also führende und endende Whitespaces.
Gruss,
Philip
--
The C Programming Quiz
- bitte Fragen einreichen :)
[EDIT] - Re: trim()
scusi71 am 22.10.2008 um 15:06
1. Warum benutzt Du WHITEPACES wenn doch in ctype.h isspace() bzw. isblank() definiert werden.
2. Wenn Du WHITEPACES brauchst, weil Du Zeichen ignorieren willst die isspace nicht für ein Whitespace hält, warum muss es dann umbedingt über den Präprozessor sein? Im Debugger sieht man dann den Inhalt nämlich nicht. Besser ist folgendes
static const char WHITESPACES[] = " \t\n\r\x0B"
Das '\0' hab ich mal entfernt, das ist in jedem C-String einmal enthalten und sollte auch nicht enfernt werden - was es durch deine Implementierung ja auch nicht wird.
3. Wenn Du alle in einem String enthaltenen Zeichen überspringen willst, dann liefert die C-Bibliothek mit strspn schon eine entsprechende Funktion.
first = strspn(s, WHITESPACES);
4. Array Indices sollten besser vom Typ size_t sein.
5. Funktionsnamen die mit str beginnen sind reserviert für Erweiterungen der Standardbibliothek.
6. Anstelle s nur auf NULL zu testen kann hier gleich der Sonderfall des leeren Strings abgetestet werden also
if (NULL == s || '\000' = *s)
return;
7. Deine Schleifen sind etwas unkoventionell programmiert, was spricht eigentlich gegen eine zweite Bedingung in der Schleife? Ausserdem liefert strlen keinen int sondern einen size_t zurück, string_last_nonwhite(char *s) funktioniert daher für lange Zeichenketten nicht. Und in string_first_nonwhite() kann es auch zum Überlauf von i kommen.
8. Der Aufruf von memmove ist nur notwendig wenn first != 0 ist.
9. Die Routine kommt mit Zeichenkette der Länge 1 nicht zurecht.
Ich habe einfach mal in meiner Codesammlung nachgeschaut. Hier ein trim mit der Möglichkeit nur am Anfang, nur am Ende oder an beiden Enden zu trimmen.
#ifndef TRIM_H_INCLUDED
#define TRIM_H_INCLUDED
typedef enum trim_mode
{
TRIM_NONE,
TRIM_FRONT,
TRIM_END,
TRIM_FRONT_END // == TRIM_FRONT | TRIM_END
} trim_mode_t;
extern char * trim (char *const restrict text,
const trim_mode_t mode);
#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char * trim (char *const restrict text,
const trim_mode_t mode)
{
if (text && *text && TRIM_NONE != mode)
{
register size_t size = strlen (text);
register char * current = text + size - 1;
if ((mode & TRIM_END))
{
while (text != current && isspace(*current))
--current, --size;
// text am letzten whitespace beenden.
current[isspace(*current) ? 0 : 1] = '\000';
}
if ((mode & TRIM_FRONT))
{
current = text;
while (*current && isspace(*current))
++current, --size;
if (text != current)
memmove (text, current, size + 1);
}
}
return text;
}
Re: trim()
broesel (webmaster) am 23.10.2008 um 18:19
Habe mich also von Dir inspirieren lassen (und die Reminiszenzen an C99 entfernt):
char *trim_front(char *const s)
{
size_t len;
char *cur;
if(s && *s) {
len = strlen(s);
cur = s;
while(*cur && isspace(*cur))
++cur, --len;
if(s != cur)
memmove(s, cur, len + 1);
}
return s;
}
char *trim_back(char *const s)
{
size_t len;
char *cur;
if(s && *s) {
len = strlen(s);
cur = s + len - 1;
while(cur != s && isspace(*cur))
--cur, --len;
cur[isspace(*cur) ? 0 : 1] = '\0';
}
return s;
}
char *trim(char *const s)
{
trim_front(s);
trim_back(s);
return s;
}
Das Schlüsselwort "extern" hat übrigens bei Funktionen/Prototypen keine Bedeutung und kann weggelassen werden.
Danke+Gruss,
Philip
--
The C Programming Quiz
- bitte Fragen einreichen :)
Re: trim()
scusi71 am 24.10.2008 um 09:21
Ansonsten sind unsere beiden Varianten ja mehr oder weniger äquivalent. Ich hatte es damals lediglich in einer Funktion zusammengezogen weil ich mir damit einen strlen Aufruf gespart habe und weil die Steuerung per Parameter für meine Belange etwas mehr flexibilität gebracht hat.
Allerdings hab ich immer noch zwei Anmerkungen
1. Warum definierst Du die Variablen schon wenn Du Sie u.U. gar nicht brauchst?
2. Du solltest Die Reihenfolge der Aufrufe in trim() verändern, beim trim_back() ändert das nichts, aber beim trim_front musst Du dann u.U. weniger verschieben.
Re: trim()
Martin Conrad (webmaster) am 24.10.2008 um 11:06
Zitat:
Ich hatte es damals lediglich in einer Funktion zusammengezogen weil ich mir damit einen strlen Aufruf gespart habe und weil die Steuerung per Parameter für meine Belange etwas mehr flexibilität gebracht hat.
Daraus ein ganzes Set zu machen ist garnicht übel. Es gibt Situationen, wo man nur eine Seite trimmen will. Im Datenbankbereich z.B...
Mir würde im Set sogar etwas fehlen. Die Funktion trim() würde bei mir trim_both() heissen, um syntaktisch einigermassen ähnlich zu anderen Funktionen zu bleiben.
Die Funktion trim() wäre vom type size_t definiert, der die neue Länge zurückgibt und würde den neuen String in den übergebenen Pointer schreiben, mit Längenangabe, bis wohin gearbeitet werden soll.
size_t trim(char *s, size_t len);
Eine Terminierung würde ich hier nur machen, insofern *s auch vorher innerhalb len terminiert war.
Für Datenbankanwendungen gibts da die ein oder Andere Anwendungsmöglichkeit...
Bis denne
Martin
--
0xC0FFEE
