Existe-t-il une méthode propre, de préférence standard, pour rogner les espaces avant et arrière d’une chaîne dans C? Je roule moi-même, mais je pense que c'est un problème commun avec une solution tout aussi commune.
Réponses
Trop de publicités?Si vous pouvez modifier la chaîne:
// Note: This function returns a pointer to a substring of the original string.
// If the given string was allocated dynamically, the caller must not overwrite
// that pointer with the returned value, since the original pointer must be
// deallocated using the same allocator with which it was allocated. The return
// value must NOT be deallocated using free() etc.
char *trimwhitespace(char *str)
{
char *end;
// Trim leading space
while(isspace(*str)) str++;
if(*str == 0) // All spaces?
return str;
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace(*end)) end--;
// Write new null terminator
*(end+1) = 0;
return str;
}
Si vous ne pouvez pas modifier la chaîne, vous pouvez utiliser essentiellement la même méthode:
// Stores the trimmed input string into the given output buffer, which must be
// large enough to store the result. If it is too small, the output is
// truncated.
size_t trimwhitespace(char *out, size_t len, const char *str)
{
if(len == 0)
return 0;
const char *end;
size_t out_size;
// Trim leading space
while(isspace(*str)) str++;
if(*str == 0) // All spaces?
{
*out = 0;
return 1;
}
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace(*end)) end--;
end++;
// Set output size to minimum of trimmed string length and buffer size minus 1
out_size = (end - str) < len-1 ? (end - str) : len-1;
// Copy trimmed string and add null terminator
memcpy(out, str, out_size);
out[out_size] = 0;
return out_size;
}
Voici celui qui déplace la chaîne dans la première position de votre tampon. Vous voudrez peut-être ce comportement afin que si vous allouez dynamiquement la chaîne, vous pouvez toujours la libérer sur le même pointeur que trim ():
char *trim(char *str)
{
size_t len = 0;
char *frontp = str - 1;
char *endp = NULL;
if( str == NULL )
return NULL;
if( str[0] == '\0' )
return str;
len = strlen(str);
endp = str + len;
/* Move the front and back pointers to address
* the first non-whitespace characters from
* each end.
*/
while( isspace(*(++frontp)) );
while( isspace(*(--endp)) && endp != frontp );
if( str + len - 1 != endp )
*(endp + 1) = '\0';
else if( frontp != str && endp == frontp )
*str = '\0';
/* Shift the string so that it starts at str so
* that if it's dynamically allocated, we can
* still free it on the returned pointer. Note
* the reuse of endp to mean the front of the
* string buffer now.
*/
endp = str;
if( frontp != str )
{
while( *frontp ) *endp++ = *frontp++;
*endp = '\0';
}
return str;
}
Je l'ai même testé pour l'exactitude:
int main(int argc, char *argv[])
{
char *sample_strings[] =
{
"nothing to trim",
" trim the front",
"trim the back ",
" trim one char front and back ",
" trim one char front",
"trim one char back ",
" ",
" ",
"a",
"",
NULL
};
char test_buffer[64];
int index;
for( index = 0; sample_strings[index] != NULL; ++index )
{
strcpy( test_buffer, sample_strings[index] );
printf("[%s] -> [%s]\n", sample_strings[index],
trim(test_buffer));
}
/* The test prints the following:
[nothing to trim] -> [nothing to trim]
[ trim the front] -> [trim the front]
[trim the back ] -> [trim the back]
[ trim one char front and back ] -> [trim one char front and back]
[ trim one char front] -> [trim one char front]
[trim one char back ] -> [trim one char back]
[ ] -> []
[ ] -> []
[a] -> [a]
[] -> []
*/
return 0;
}
Le fichier source était trim.c. Compilé avec 'cc trim.c -o trim'.
Ma solution La chaîne doit être modifiable. L’avantage, au-dessus des autres solutions, est de déplacer la partie non-espace au début pour que vous puissiez continuer à utiliser l’ancien pointeur, au cas où vous deviez le libérer plus tard.
void trim(char * s) {
char * p = s;
int l = strlen(p);
while(isspace(p[l - 1])) p[--l] = 0;
while(* p && isspace(* p)) ++p, --l;
memmove(s, p, l + 1);
}
Cette version crée une copie de la chaîne avec strndup () au lieu de la modifier sur place. strndup () nécessite _GNU_SOURCE, alors peut-être avez-vous besoin de créer votre propre strndup () avec malloc () et strncpy ().
char * trim(char * s) {
int l = strlen(s);
while(isspace(s[l - 1])) --l;
while(* s && isspace(* s)) ++s, --l;
return strndup(s, l);
}
Voici mon C mini bibliothèque pour coupe à gauche, à droite, à la fois, tous les, en place et distincte, et la coupe d'un ensemble de caractères (ou en blanc par défaut).
contenu de strlib.h:
#ifndef STRLIB_H_
enum strtrim_mode_t {
STRLIB_MODE_ALL = 0,
STRLIB_MODE_RIGHT = 0x01,
STRLIB_MODE_LEFT = 0x02,
STRLIB_MODE_BOTH = 0x03
};
char *strcpytrim(char *d, // destination
char *s, // source
int mode,
char *delim
);
char *strtriml(char *d, char *s);
char *strtrimr(char *d, char *s);
char *strtrim(char *d, char *s);
char *strkill(char *d, char *s);
char *triml(char *s);
char *trimr(char *s);
char *trim(char *s);
char *kill(char *s);
#endif
contenu de strlib.c:
#include <strlib.h>
char *strcpytrim(char *d, // destination
char *s, // source
int mode,
char *delim
) {
char *o = d; // save orig
char *e = 0; // end space ptr.
char dtab[256] = {0};
if (!s || !d) return 0;
if (!delim) delim = " \t\n\f";
while (*delim)
dtab[*delim++] = 1;
while ( (*d = *s++) != 0 ) {
if (!dtab[*d]) { // Not a match char
e = 0; // Reset end pointer
} else {
if (!e) e = d; // Found first match.
if ( mode == STRLIB_MODE_ALL || ((mode != STRLIB_MODE_RIGHT) && (d == o)) )
continue;
}
d++;
}
if (mode != STRLIB_MODE_LEFT && e) { // for everything but trim_left, delete trailing matches.
*e = 0;
}
return o;
}
// perhaps these could be inlined in strlib.h
char *strtriml(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_LEFT, 0); }
char *strtrimr(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_RIGHT, 0); }
char *strtrim(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_BOTH, 0); }
char *strkill(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_ALL, 0); }
char *triml(char *s) { return strcpytrim(s, s, STRLIB_MODE_LEFT, 0); }
char *trimr(char *s) { return strcpytrim(s, s, STRLIB_MODE_RIGHT, 0); }
char *trim(char *s) { return strcpytrim(s, s, STRLIB_MODE_BOTH, 0); }
char *kill(char *s) { return strcpytrim(s, s, STRLIB_MODE_ALL, 0); }
Une routine principale tout faire.
Il garnitures en place si src == dst, sinon,
il fonctionne comme l' strcpy
des routines.
Il réduit à un jeu de caractères spécifié dans la chaîne delim, ou en blanc si la valeur est null.
Il garnitures à gauche, à droite, à la fois, et tous (comme tr).
Il n'y a pas beaucoup à elle, et il parcourt la chaîne qu'une seule fois. Certaines personnes pourraient se plaindre que de la garniture à droite démarre sur la gauche, en revanche, aucune strlen est nécessaire qui démarre sur la gauche de toute façon. (D'une façon ou d'une autre, vous devez obtenir à la fin de la chaîne pour le droit de garnitures, de sorte que vous pourriez aussi bien faire le travail que vous allez.) Il peut y avoir des arguments à propos de pipeline et les tailles de cache et tel, qui sait. Étant donné que la solution fonctionne de gauche à droite et réitère qu'une seule fois, il peut être étendu à des travaux sur les cours d'eau. Limites: elle n'a pas de travail sur unicode cordes.
Voici ma tentative pour une fonction de coupe simple, mais correcte.
void trim(char *str)
{
int i;
int begin = 0;
int end = strlen(str) - 1;
while (isspace(str[begin]))
begin++;
while ((end >= begin) && isspace(str[end]))
end--;
// Shift all characters back to the start of the string array.
for (i = begin; i <= end; i++)
str[i - begin] = str[i];
str[i - begin] = '\0'; // Null terminate string.
}