Chinaunix首页 | 论坛 | 博客
  • 博客访问: 458290
  • 博文数量: 68
  • 博客积分: 2606
  • 博客等级: 上尉
  • 技术积分: 1308
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-13 23:01
文章分类
文章存档

2012年(6)

2011年(62)

分类: C/C++

2011-09-11 13:51:47

------------------------------------------
本文为本人原创,欢迎转载!
转载请注明出处:snowboy.blog.chinaunix.net
雪夜流星
------------------------------------------
本文针对实现去除字符串左右空格的功能进行探讨,在牛人代码的基础上进行改进并加以注释。本文参照了cu论坛flw的精华帖,在此表示感谢:
源实现如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. /*****************************************************************
  4.  *函数功能:去除字符串左右两边的空格

  5.  *传入参数:str:需要处理的字符串

  6.  *传出参数:无(由于传入的是指针,形参指向元素的改变将影响实参)

  7.  *返回值:无

  8.  *******************************************************************/
  9. void trim( char *str )
  10. {
  11.         char *copied, *tail = NULL;
  12.     
  13.     /*判空*/
  14.         if ( str == NULL )
  15.                 return;
  16.     
  17.     /*去除字符串左边空格,并找到字符串右边的第一个空格*/
  18.         for( copied = str; *str; str++ )
  19.         {
  20.             /*当前字符不为空格时,将当前字符拷贝到新的字符串中,并更新tail指针指向的空间
  21.              为新字符串的尾部*/
  22.                 if ( *str != ' ' && *str != '\t' )
  23.                 {
  24.                         *copied++ = *str;
  25.                          tail = copied;
  26.                 }
  27.                 else
  28.                 {    
  29.                      /*当tail不为空时,将当前字符拷贝到新的字符串中:由于tail初值为NULL,
  30.                      找到第一个非空格字符时才会将其值更新,所以能够保证去除字符串左边
  31.                      的空格,而保留中间和右边的空格*/
  32.                          if ( tail )
  33.                                  *copied++ = *str;
  34.                 }
  35.         }
  36.     
  37.     /*去除字符串右边的空格:如果tail非空,则将tail赋'\0'(将其后的字符截断);
  38.      否则将字符串清空(即传入字符串全为空格)*/
  39.         if ( tail )
  40.              *tail = 0;
  41.         else
  42.              *copied = 0;

  43.         return;
  44. }

  45. int main(void)
  46. {
  47.     char string[100] = " abcd ef gh -- ijk ";
  48.     trim(string);
  49.     printf(string);
  50.     printf("\n");

  51.     return 0;
  52. }
由于上面的代码需要移动字符串中元素,可能效率较慢,本人的思路是将第一个非空格字符处做一
标记(将一局部指针指向此处),找到右边第一个空格并将其赋值为字符串结束符。最后返回局部指针。程序实现如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. /*************************************************
  4.  *函数功能:去除字符串左右两边的空格

  5.  *传入参数:str:需要处理的字符串

  6.  *传出参数:无

  7.  *返回值:处理后的字符串

  8.  ************************************************/
  9. char * trim( char *str )
  10. {
  11.     char *head, *tail = NULL;
  12.     
  13.     if ( str == NULL )
  14.         return str;
  15.     
  16.     for( head = str; *str; str++ )
  17.     {
  18.         if ( *str != ' ' && *str != '\t' )
  19.         {            
  20.             if (tail == NULL)
  21.             {
  22.                 head = str;//tail为NULL时,此处为第一个非空格字符,将此位置保存下来
  23.             }
  24.             tail = str+1;//更新tail指针的指向为非空格字符的下一个位置
  25.         }        
  26.     }
  27.     /*由于tail始终指向非空格字符的下一个位置,当循环退出时,tail指向右边第一个空格*/
  28.     if ( tail )
  29.         *tail = 0;
  30.     else
  31.         *head = 0;
  32.     
  33.     return head;
  34. }

  35. int main(void)
  36. {
  37.     char string[100] = " abcd ef gh -- ijk ";
  38.     char * p = trim(string);
  39.     printf(p);
  40.     printf("\n");

  41.     return 0;
  42. }
除了上面这种思路,还有一种思路是“从前往后数掉前面的空格”,再“从后往前数掉后面的空格”,等“数”出了实际有效的第一个字符和最后一个字符之后,再用 strcpy 或者 memcpy 拷贝过去。
本人思路:
char *trim(char *str)
{
int i = 0;
int j = 0;
int len = strlen(str);

assert(str !=NULL && len>0);

for (i = 0; i
{
if (*(str+i) != ' ' && *(str+i) != '\t')
{
break;
}
}
for (j = len-1; j>=0; j--)
{
if (*(str+j) !=' ' && *(str+j) != '\t')
{
break;
}
}
*(str+j+1) = '\0';

return str+i;//等价于return memmove(str,str+i,j-i+2);此处其实亦可以用memcpy(参考其实现)
}
事实上,Trim 从算法上来讲,也就这两个思路,大多数人采用的是后面的这个思路,好像依赖于 strlen、memcpy 等库函数的效率后,反而要更快些。而上面的那个思路,似乎没有多少人去想,结果就吃亏在“效率”问题上了。
关于第二种思路在此不再继续探讨,如果有兴趣可以参照文章:
上面这边文章中的不足是,最后的memcpy函数源和目的地址存在重叠情况,结果依赖于实现,应该使用memmove。
阅读(8614) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~