如何以标准方式修剪前导/尾随空格?

有没有一个干净的,最好是标准的方法来修剪从C中的string的前导和尾随空白? 我会推出自己的,但我认为这是一个同样常见的解决scheme的常见问题。

如果你可以修改string:

// 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((unsigned char)*str)) str++; if(*str == 0) // All spaces? return str; // Trim trailing space end = str + strlen(str) - 1; while(end > str && isspace((unsigned char)*end)) end--; // Write new null terminator *(end+1) = 0; return str; } 

如果你不能修改string,那么你可以使用基本相同的方法:

 // 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((unsigned char)*str)) str++; if(*str == 0) // All spaces? { *out = 0; return 1; } // Trim trailing space end = str + strlen(str) - 1; while(end > str && isspace((unsigned char)*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; } 

这是一个将string转换为缓冲区的第一个位置的string。 您可能需要这种行为,以便如果您dynamic分配string,仍然可以将其释放在trim()返回的指针上:

 char *trim(char *str) { size_t len = 0; char *frontp = str; 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((unsigned char) *frontp) ) { ++frontp; } if( endp != frontp ) { while( isspace((unsigned char) *(--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; } 

testing正确性:

 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; } 

源文件是trim.c. 用'cc trim.c -o trim'编译。

我的解决scheme string必须是可变的。 上面提到的一些其他解决scheme的优点是,它将非空间部分移动到开始位置,以便您可以继续使用旧的指针,以防以后需要释放()。

 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); } 

该版本使用strndup()创build了一个string的副本,而不是在原地进行编辑。 strndup()需要_GNU_SOURCE,所以也许你需要用malloc()和strncpy()来创build自己的strndup()。

 char * trim(char * s) { int l = strlen(s); while(isspace(s[l - 1])) --l; while(* s && isspace(* s)) ++s, --l; return strndup(s, l); } 

这是我的尝试,在一个简单,但正确的就地修剪function。

 void trim(char *str) { int i; int begin = 0; int end = strlen(str) - 1; while (isspace((unsigned char) str[begin])) begin++; while ((end >= begin) && isspace((unsigned char) 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. } 

这里是我的C迷你库,左,右,两个,所有,就地和分离,修剪一组指定的字符(或白色空间默认)。

strlib.h的内容:

 #ifndef STRLIB_H_ #define STRLIB_H_ 1 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 

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[0xFF & (unsigned int)*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); } 

一个主要的例程完成了这一切。 它修剪的地方如果src == dst ,否则,它就像strcpy例程。 它修剪在stringdelim中指定的一组字符,如果为空则为空白。 它修剪左,右,两个,和所有(如tr)。 没有太多的东西,它只遍历string一次。 有些人可能会抱怨,修剪权从左边开始,但是,无论如何,都不需要从左边开始的strlen。 (不pipe怎么样,你必须得到string的最后部分才能进行正确的修剪,所以你不妨做一些工作。)可能会有关于stream水线和caching大小的争论 – 谁知道。 由于该解决scheme从左到右工作并且只迭代一次,所以它也可以扩展到在stream上工作。 限制:它不适用于unicodestring。

这里有一个类似于@adam-rosenfields in-place修改例程的解决scheme,但是不需要诉诸strlen()。 就像@jkramer一样,这个string在缓冲区内是左边的,所以你可以释放相同的指针。 由于不使用memmove,因此不适用于大型string。 包括@ jfm3提到的++ / – 运算符。 包括基于FCTX的unit testing。

 #include <ctype.h> void trim(char * const a) { char *p = a, *q = a; while (isspace(*q)) ++q; while (*q) *p++ = *q++; *p = '\0'; while (p > a && isspace(*--p)) *p = '\0'; } /* See http://fctx.wildbearsoftware.com/ */ #include "fct.h" FCT_BGN() { FCT_QTEST_BGN(trim) { { char s[] = ""; trim(s); fct_chk_eq_str("", s); } // Trivial { char s[] = " "; trim(s); fct_chk_eq_str("", s); } // Trivial { char s[] = "\t"; trim(s); fct_chk_eq_str("", s); } // Trivial { char s[] = "a"; trim(s); fct_chk_eq_str("a", s); } // NOP { char s[] = "abc"; trim(s); fct_chk_eq_str("abc", s); } // NOP { char s[] = " a"; trim(s); fct_chk_eq_str("a", s); } // Leading { char s[] = " ac"; trim(s); fct_chk_eq_str("ac", s); } // Leading { char s[] = "a "; trim(s); fct_chk_eq_str("a", s); } // Trailing { char s[] = "ac "; trim(s); fct_chk_eq_str("ac", s); } // Trailing { char s[] = " a "; trim(s); fct_chk_eq_str("a", s); } // Both { char s[] = " ac "; trim(s); fct_chk_eq_str("ac", s); } // Both // Villemoes pointed out an edge case that corrupted memory. Thank you. // http://stackoverflow.com/questions/122616/#comment23332594_4505533 { char s[] = "a "; // Buffer with whitespace before s + 2 trim(s + 2); // Trim " " containing only whitespace fct_chk_eq_str("", s + 2); // Ensure correct result from the trim fct_chk_eq_str("a ", s); // Ensure preceding buffer not mutated } // doukremt suggested I investigate this test case but // did not indicate the specific behavior that was objectionable. // http://stackoverflow.com/posts/comments/33571430 { char s[] = " foobar"; // Shifted across whitespace trim(s); // Trim fct_chk_eq_str("foobar", s); // Leading string is correct // Here is what the algorithm produces: char r[16] = { 'f', 'o', 'o', 'b', 'a', 'r', '\0', ' ', ' ', 'f', 'o', 'o', 'b', 'a', 'r', '\0'}; fct_chk_eq_int(0, memcmp(s, r, sizeof(s))); } } FCT_QTEST_END(); } FCT_END(); 

迟到的派对

特征:
1.快速修改开始,就像其他一些答案一样。
2.完成后,每个循环只进行一次testing。 像@ jfm3一样,但适用于所有的空白string)
3.当char是一个有符号的char ,为了避免未定义的行为,将*sunsigned char

字符处理 “在任何情况下,参数都是一个int值,它的值可以表示为一个unsigned char或者等于macrosEOF的值,如果该参数有任何其他值,那么行为是不确定的。 C11§7.41

 #include <ctype.h> // Return a pointer to the trimmed string char *string_trim_inplace(char *s) { while (isspace((unsigned char) *s)) s++; if (*s) { char *p = s; while (*p) p++; while (isspace((unsigned char) *(--p))); p[1] = '\0'; } return s; } 

另一个,一行做真正的工作:

 #include <stdio.h> int main() { const char *target = " haha "; char buf[256]; sscanf(target, "%s", buf); // Trimming on both sides occurs here printf("<%s>\n", buf); } 

我不喜欢这些答案的大部分,因为他们做了一个或多个以下…

  1. 在原始指针的string内部返回一个不同的指针(一种痛苦,把两个不同的指针混合在一起)。
  2. strlen()这样的事情做了无条件的使用,这些事先迭代整个string。
  3. 使用了非便携式操作系统特定的lib函数。
  4. Backscanned。
  5. 使用比较而不是isspace()来保存TAB / CR / LF。
  6. 浪费大量静态缓冲区的内存。
  7. sscanf / sprintf等高成本函数浪费周期。

这是我的版本:

 void fnStrTrimInPlace(char *szWrite) { const char *szWriteOrig = szWrite; char *szLastSpace = szWrite, *szRead = szWrite; int bNotSpace; // SHIFT STRING, STARTING AT FIRST NON-SPACE CHAR, LEFTMOST while( *szRead != '\0' ) { bNotSpace = !isspace((unsigned char)(*szRead)); if( (szWrite != szWriteOrig) || bNotSpace ) { *szWrite = *szRead; szWrite++; // TRACK POINTER TO LAST NON-SPACE if( bNotSpace ) szLastSpace = szWrite; } szRead++; } // TERMINATE AFTER LAST NON-SPACE (OR BEGINNING IF THERE WAS NO NON-SPACE) *szLastSpace = '\0'; } 

使用一个string库 ,例如:

 Ustr *s1 = USTR1(\7, " 12345 "); ustr_sc_trim_cstr(&s1, " "); assert(ustr_cmp_cstr_eq(s1, "12345")); 

…正如你所说这是一个“常见”的问题,是的,你需要包括#include左右,它不包括在libc中,但不要去发明自己的黑客工作,存储随机指针和size_t的方式只会导致缓冲区溢出。

 #include "stdafx.h" #include "malloc.h" #include "string.h" int main(int argc, char* argv[]) { char *ptr = (char*)malloc(sizeof(char)*30); strcpy(ptr," Hel lo wo rl d G eo rocks!!! by shahil sucks big tim e"); int i = 0, j = 0; while(ptr[j]!='\0') { if(ptr[j] == ' ' ) { j++; ptr[i] = ptr[j]; } else { i++; j++; ptr[i] = ptr[j]; } } printf("\noutput-%s\n",ptr); return 0; } 

我非常高兴,我想说我很高兴这篇文章是可用的,并展示了我能够用这些例子做的事情。 我需要标记一个更大的string,然后取出子string并find最后一个 – 所以我可以从fgets()调用中删除一个换行符,并且还从该标记的前面删除空白 – 所以我可以很容易比较它与一个静态string。 上面的post中的第一个例子让我在那里,所以谢谢你。 这是我如何使用代码示例和我得到的输出。

 int _tmain(int argc, _TCHAR* argv[]) { FILE * fp; // test file char currDBSStatstr[100] = {"/0"}; char *beg; char *end; char *str1; char str[] = "Initializing DBS Configuration"; fp = fopen("file2-1.txt","r"); if (fp != NULL) { printf("File exists.\n"); fgets(currDBSStatstr, sizeof(currDBSStatstr), fp); } else { printf("Error.\n"); exit(2); } //print string printf("String: %s\n", currDBSStatstr); //extract first string str1 = strtok(currDBSStatstr, ":-"); //print first token printf("%s\n", str1); //get more tokens in sequence while(1) { //extract more tokens in sequence str1 = strtok(NULL, ":-"); //check to see if done if (str1 == NULL) { printf("Tokenizing Done.\n"); exit(0); } //print string after tokenizing Done printf("%s\n", str1); end = str1 + strlen(str1) - 1; while((end > str1) && (*end == '\n')) { end--; *(end+1) = 0; beg = str1; while(isspace(*str1)) str1++; } printf("%s\n", str1); if (strcmp(str, str1) == 0) printf("Strings are equal.\n"); } return 0; 

}

产量

文件已存在。

string:DBS状态:DBS启动 – 初始化DBSconfiguration

星展银行州

DBS启动

DBS启动

初始化DBSconfiguration

初始化DBSconfiguration

string是平等的。

完成标记。

如果你使用的是glib ,那么你可以使用g_strstrip

为了保持这种增长,还有一个可修改string的选项:

 void trimString(char *string) { size_t i = 0, j = strlen(string); while (j > 0 && isspace((unsigned char)string[j - 1])) string[--j] = '\0'; while (isspace((unsigned char)string[i])) i++; if (i > 0) memmove(string, string + i, j - i + 1); } 

它与正则expression式库的微不足道,所以我们在说什么“纯”C?

就我个人而言,我会推出自己的。 你可以使用strtok,但是你需要注意这样做(特别是如果你删除主angular),你知道什么是内存。

摆脱尾随空格很容易,而且非常安全,因为您可以将0放在最后一个空格的顶部,从末尾开始计数。 摆脱领先的空间意味着移动的东西。 如果你想做到这一点(可能是合理的),你可以继续把所有的东西都转移回去,直到没有领先的空间。 或者,为了更有效率,您可以find第一个非空格字符的索引,并将所有内容都移回该数字。 或者,您可以使用指向第一个非空格字符的指针(但是您需要像使用strtok一样小心)。

我不确定你认为“无痛”。

Cstring非常痛苦。 我们可以简单地find第一个非空白字符位置:

 while(isspace(* p))p ++;

我们可以用两个相似的平凡动作find最后一个非空白字符位置:

 while(* q)q ++;
做{q--;  (isspace(* q));

(我已经免除了同时使用*++运算符的痛苦。)

现在的问题是你用这个做什么? 手头的数据types实际上不是一个很好的抽象String ,很容易思考,但实际上只是一个存储字节数组。 缺乏一个健壮的数据types,就不可能编写一个和PHperytonby的chomp函数一样的函数。 C中的这个函数返回什么?

比赛迟到了一点,但我会把我的例程投入到战斗中。 他们可能不是最绝对有效的,但我相信他们是正确的,他们很简单(用rtrim()推动复杂的信封):

 #include <ctype.h> #include <string.h> /* Public domain implementations of in-place string trim functions Michael Burr michael.burr@nth-element.com 2010 */ char* ltrim(char* s) { char* newstart = s; while (isspace( *newstart)) { ++newstart; } // newstart points to first non-whitespace char (which might be '\0') memmove( s, newstart, strlen( newstart) + 1); // don't forget to move the '\0' terminator return s; } char* rtrim( char* s) { char* end = s + strlen( s); // find the last non-whitespace character while ((end != s) && isspace( *(end-1))) { --end; } // at this point either (end == s) and s is either empty or all whitespace // so it needs to be made empty, or // end points just past the last non-whitespace character (it might point // at the '\0' terminator, in which case there's no problem writing // another there). *end = '\0'; return s; } char* trim( char* s) { return rtrim( ltrim( s)); } 

到目前为止,大部分的答案都是以下的一种:

  1. 在string的末尾回溯(即findstring的末尾,然后向后寻找,直到find非空格字符)或
  2. 首先调用strlen() ,第二遍遍历整个string。

这个版本只有一个通行证,不会回溯。 因此,它可能比其他的performance更好,但是只有在数百个尾随空格的情况下(这在处理SQL查询的输出时并不罕见)。

 static char const WHITESPACE[] = " \t\n\r"; static void get_trim_bounds(char const *s, char const **firstWord, char const **trailingSpace) { char const *lastWord; *firstWord = lastWord = s + strspn(s, WHITESPACE); do { *trailingSpace = lastWord + strcspn(lastWord, WHITESPACE); lastWord = *trailingSpace + strspn(*trailingSpace, WHITESPACE); } while (*lastWord != '\0'); } char *copy_trim(char const *s) { char const *firstWord, *trailingSpace; char *result; size_t newLength; get_trim_bounds(s, &firstWord, &trailingSpace); newLength = trailingSpace - firstWord; result = malloc(newLength + 1); memcpy(result, firstWord, newLength); result[newLength] = '\0'; return result; } void inplace_trim(char *s) { char const *firstWord, *trailingSpace; size_t newLength; get_trim_bounds(s, &firstWord, &trailingSpace); newLength = trailingSpace - firstWord; memmove(s, firstWord, newLength); s[newLength] = '\0'; } 

这是我能想到的最短的实现:

 static const char *WhiteSpace=" \n\r\t"; char* trim(char *t) { char *e=t+(t!=NULL?strlen(t):0); // *e initially points to end of string if (t==NULL) return; do --e; while (strchr(WhiteSpace, *e) && e>=t); // Find last char that is not \r\n\t *(++e)=0; // Null-terminate e=t+strspn (t,WhiteSpace); // Find first char that is not \t return e>t?memmove(t,e,strlen(e)+1):t; // memmove string contents and terminator } 

这些函数将修改原始缓冲区,所以如果dynamic分配,可以释放原始指针。

 #include <string.h> void rstrip(char *string) { int l; if (!string) return; l = strlen(string) - 1; while (isspace(string[l]) && l >= 0) string[l--] = 0; } void lstrip(char *string) { int i, l; if (!string) return; l = strlen(string); while (isspace(string[(i = 0)])) while(i++ < l) string[i-1] = string[i]; } void strip(char *string) { lstrip(string); rstrip(string); } 

你在使用Shlwapi.h头文件中定义的StrTrim函数时有什么想法? 这是直接的,而是自己定义。
详情可在以下urlfind:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773454(v=vs.85).aspx

如果你有
char ausCaptain[]="GeorgeBailey ";
StrTrim(ausCaptain," ");
这将使ausCaptain成为"GeorgeBailey"而不是"GeorgeBailey "

从两边修剪我的琴弦,我使用oldie,但使用gooody;)它可以修剪ascii小于一个空间的任何东西,这意味着控制字符也将被修剪!

 char *trimAll(char *strData) { unsigned int L = strlen(strData); if(L > 0){ L--; }else{ return strData; } size_t S = 0, E = L; while((!(strData[S] > ' ') || !(strData[E] > ' ')) && (S >= 0) && (S <= L) && (E >= 0) && (E <= L)) { if(strData[S] <= ' '){ S++; } if(strData[E] <= ' '){ E--; } } if(S == 0 && E == L){ return strData; } // Nothing to be done if((S >= 0) && (S <= L) && (E >= 0) && (E <= L)){ L = E - S + 1; memmove(strData,&strData[S],L); strData[L] = '\0'; }else{ strData[0] = '\0'; } return strData; } 

I'm only including code because the code posted so far seems suboptimal (and I don't have the rep to comment yet.)

 void inplace_trim(char* s) { int start, end = strlen(s); for (start = 0; isspace(s[start]); ++start) {} if (s[start]) { while (end > 0 && isspace(s[end-1])) --end; memmove(s, &s[start], end - start); } s[end - start] = '\0'; } char* copy_trim(const char* s) { int start, end; for (start = 0; isspace(s[start]); ++start) {} for (end = strlen(s); end > 0 && isspace(s[end-1]); --end) {} return strndup(s + start, end - start); } 

strndup() is a GNU extension. If you don't have it or something equivalent, roll your own. 例如:

 r = strdup(s + start); r[end-start] = '\0'; 

I know there have many answers, but I post my answer here to see if my solution is good enough.

 // Trims leading whitespace chars in left `str`, then copy at almost `n - 1` chars // into the `out` buffer in which copying might stop when the first '\0' occurs, // and finally append '\0' to the position of the last non-trailing whitespace char. // Reture the length the trimed string which '\0' is not count in like strlen(). size_t trim(char *out, size_t n, const char *str) { // do nothing if(n == 0) return 0; // ptr stop at the first non-leading space char while(isspace(*str)) str++; if(*str == '\0') { out[0] = '\0'; return 0; } size_t i = 0; // copy char to out until '\0' or i == n - 1 for(i = 0; i < n - 1 && *str != '\0'; i++){ out[i] = *str++; } // deal with the trailing space while(isspace(out[--i])); out[++i] = '\0'; return i; } 

Here is a function to do what you want. It should take care of degenerate cases where the string is all whitespace. You must pass in an output buffer and the length of the buffer, which means that you have to pass in a buffer that you allocate.

 void str_trim(char *output, const char *text, int32 max_len) { int32 i, j, length; length = strlen(text); if (max_len < 0) { max_len = length + 1; } for (i=0; i<length; i++) { if ( (text[i] != ' ') && (text[i] != '\t') && (text[i] != '\n') && (text[i] != '\r')) { break; } } if (i == length) { // handle lines that are all whitespace output[0] = 0; return; } for (j=length-1; j>=0; j--) { if ( (text[j] != ' ') && (text[j] != '\t') && (text[j] != '\n') && (text[j] != '\r')) { break; } } length = j + 1 - i; strncpy(output, text + i, length); output[length] = 0; } 

The if statements in the loops can probably be replaced with isspace(text[i]) or isspace(text[j]) to make the lines a little easier to read. I think that I had them set this way because there were some characters that I didn't want to test for, but it looks like I'm covering all whitespace now 🙂

 #include<stdio.h> #include<ctype.h> main() { char sent[10]={' ',' ',' ','s','t','a','r','s',' ',' '}; int i,j=0; char rec[10]; for(i=0;i<=10;i++) { if(!isspace(sent[i])) { rec[j]=sent[i]; j++; } } printf("\n%s\n",rec); } 

Here is what I disclosed regarding the question in Linux kernel code:

 /** * skip_spaces - Removes leading whitespace from @s. * @s: The string to be stripped. * * Returns a pointer to the first non-whitespace character in @s. */ char *skip_spaces(const char *str) { while (isspace(*str)) ++str; return (char *)str; } /** * strim - Removes leading and trailing whitespace from @s. * @s: The string to be stripped. * * Note that the first trailing whitespace is replaced with a %NUL-terminator * in the given string @s. Returns a pointer to the first non-whitespace * character in @s. */ char *strim(char *s) { size_t size; char *end; size = strlen(s); if (!size) return s; end = s + size - 1; while (end >= s && isspace(*end)) end--; *(end + 1) = '\0'; return skip_spaces(s); } 

It is supposed to be bug free due to the origin 😉

Mine one piece is closer to KISS principle I guess:

 /** * trim spaces **/ char * trim_inplace(char * s, int len) { // trim leading while (len && isspace(s[0])) { s++; len--; } // trim trailing while (len && isspace(s[len - 1])) { s[len - 1] = 0; len--; } return s; } 

C++ STL style

 std::string Trimed(const std::string& s) { std::string::const_iterator begin = std::find_if(s.begin(), s.end(), [](char ch) { return !std::isspace(ch); }); std::string::const_iterator end = std::find_if(s.rbegin(), s.rend(), [](char ch) { return !std::isspace(ch); }).base(); return std::string(begin, end); } 

http://ideone.com/VwJaq9

 void trim(char* const str) { char* begin = str; char* end = str; while (isspace(*begin)) { ++begin; } char* s = begin; while (*s != '\0') { if (!isspace(*s++)) { end = s; } } *end = '\0'; const int dist = end - begin; if (begin > str && dist > 0) { memmove(str, begin, dist + 1); } } 

Modifies string in place, so you can still delete it.

Doesn't use fancy pants library functions (unless you consider memmove fancy).

Handles string overlap.

Trims front and back (not middle, sorry).

Fast if string is large (memmove often written in assembly).

Only moves characters if required (I find this true in most use cases because strings rarely have leading spaces and often don't have tailing spaces)

I would like to test this but I'm running late. Enjoy finding bugs… 🙂