【发布时间】:2010-10-13 23:32:52
【问题描述】:
简述:
我正在使用 win32 和标准 C api 在 C 中使用相当于 .NET 的 String.Trim(使用 MSVC2008 编译,因此如果需要我可以访问所有 C++ 内容,但我只是想修剪 @987654322 @)。
鉴于有 strchr、strtok 和各种其他字符串函数,当然应该有一个修剪函数,或者可以重新调整用途的函数......
谢谢
【问题讨论】:
简述:
我正在使用 win32 和标准 C api 在 C 中使用相当于 .NET 的 String.Trim(使用 MSVC2008 编译,因此如果需要我可以访问所有 C++ 内容,但我只是想修剪 @987654322 @)。
鉴于有 strchr、strtok 和各种其他字符串函数,当然应该有一个修剪函数,或者可以重新调整用途的函数......
谢谢
【问题讨论】:
不是最好的方法,但它有效
char* Trim(char* str)
{
int len = strlen(str);
char* buff = new char[len];
int i = 0;
memset(buff,0,len*sizeof(char));
do{
if(isspace(*str)) continue;
buff[i] = *str; ++i;
} while(*(++str) != '\0');
return buff;
}
【讨论】:
void ltrim(char str[PATH_MAX])
{
int i = 0, j = 0;
char buf[PATH_MAX];
strcpy(buf, str);
for(;str[i] == ' ';i++);
for(;str[i] != '\0';i++,j++)
buf[j] = str[i];
buf[j] = '\0';
strcpy(str, buf);
}
【讨论】:
当返回值总是等于参数时,我喜欢它。这样,如果字符串数组已经分配了malloc(),它就可以安全地再次为free()。
/* Remove leading whitespaces */
char *ltrim(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;
}
/* Remove trailing whitespaces */
char *rtrim(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;
}
/* Remove leading and trailing whitespaces */
char *trim(char *const s)
{
rtrim(s); // order matters
ltrim(s);
return s;
}
【讨论】:
/* Function to remove white spaces on both sides of a string i.e trim */
void trim (char *s)
{
int i;
while (isspace (*s)) s++; // skip left side white spaces
for (i = strlen (s) - 1; (isspace (s[i])); i--) ; // skip right side white spaces
s[i + 1] = '\0';
printf ("%s\n", s);
}
【讨论】:
这是我的实现,其行为类似于 libc 中的内置字符串函数(也就是说,它需要一个 c 字符串,它对其进行修改并将其返回给调用者)。
它修剪前导空格并将剩余的字符向左移动,因为它从左到右解析字符串。然后它标记字符串的新结尾并开始向后解析,用 '\0' 替换尾随空格,直到找到非空格字符或字符串的开头。我相信这些是这个特定任务的最小可能迭代。
// ----------------------------------------------------------------------------
// trim leading & trailing spaces from string s (return modified string s)
// alg:
// - skip leading spaces, via cp1
// - shift remaining *cp1's to the left, via cp2
// - mark a new end of string
// - replace trailing spaces with '\0', via cp2
// - return the trimmed s
//
char *s_trim(char *s)
{
char *cp1; // for parsing the whole s
char *cp2; // for shifting & padding
// skip leading spaces, shift remaining chars
for (cp1=s; isspace(*cp1); cp1++ ) // skip leading spaces, via cp1
;
for (cp2=s; *cp1; cp1++, cp2++) // shift left remaining chars, via cp2
*cp2 = *cp1;
*cp2-- = 0; // mark new end of string for s
// replace trailing spaces with '\0'
while ( cp2 > s && isspace(*cp2) )
*cp2-- = 0; // pad with '\0's
return s;
}
【讨论】:
static inline void ut_trim(char * str) {
char * start = str;
char * end = start + strlen(str);
while (--end >= start) { /* trim right */
if (!isspace(*end))
break;
}
*(++end) = '\0';
while (isspace(*start)) /* trim left */
start++;
if (start != str) /* there is a string */
memmove(str, start, end - start + 1);
}
【讨论】:
#include "stdafx.h"
#include <string.h>
#include <ctype.h>
char* trim(char* input);
int _tmain(int argc, _TCHAR* argv[])
{
char sz1[]=" MQRFH ";
char sz2[]=" MQRFH";
char sz3[]=" MQR FH";
char sz4[]="MQRFH ";
char sz5[]="MQRFH";
char sz6[]="M";
char sz7[]="M ";
char sz8[]=" M";
char sz9[]="";
char sz10[]=" ";
printf("sz1:[%s] %d\n",trim(sz1), strlen(sz1));
printf("sz2:[%s] %d\n",trim(sz2), strlen(sz2));
printf("sz3:[%s] %d\n",trim(sz3), strlen(sz3));
printf("sz4:[%s] %d\n",trim(sz4), strlen(sz4));
printf("sz5:[%s] %d\n",trim(sz5), strlen(sz5));
printf("sz6:[%s] %d\n",trim(sz6), strlen(sz6));
printf("sz7:[%s] %d\n",trim(sz7), strlen(sz7));
printf("sz8:[%s] %d\n",trim(sz8), strlen(sz8));
printf("sz9:[%s] %d\n",trim(sz9), strlen(sz9));
printf("sz10:[%s] %d\n",trim(sz10), strlen(sz10));
return 0;
}
char *ltrim(char *s)
{
while(isspace(*s)) s++;
return s;
}
char *rtrim(char *s)
{
char* back;
int len = strlen(s);
if(len == 0)
return(s);
back = s + len;
while(isspace(*--back));
*(back+1) = '\0';
return s;
}
char *trim(char *s)
{
return rtrim(ltrim(s));
}
输出:
sz1:[MQRFH] 9
sz2:[MQRFH] 6
sz3:[MQR FH] 8
sz4:[MQRFH] 7
sz5:[MQRFH] 5
sz6:[M] 1
sz7:[M] 2
sz8:[M] 2
sz9:[] 0
sz10:[] 8
【讨论】:
/* iMode 0:ALL, 1:Left, 2:Right*/
char* Trim(char* szStr,const char ch, int iMode)
{
if (szStr == NULL)
return NULL;
char szTmp[1024*10] = { 0x00 };
strcpy(szTmp, szStr);
int iLen = strlen(szTmp);
char* pStart = szTmp;
char* pEnd = szTmp+iLen;
int i;
for(i = 0;i < iLen;i++){
if (szTmp[i] == ch && pStart == szTmp+i && iMode != 2)
++pStart;
if (szTmp[iLen-i-1] == ch && pEnd == szTmp+iLen-i && iMode != 1)
*(--pEnd) = '\0';
}
strcpy(szStr, pStart);
return szStr;
}
【讨论】:
这个怎么样...它只需要对字符串进行一次迭代(不使用 strlen,它对字符串进行迭代)。当函数返回时,您将获得一个指向已修剪字符串开头的指针,该字符串以空值结尾。字符串从左边开始去掉空格(直到找到第一个字符)。最后一个非空格字符之后的所有尾随空格也会被修剪掉。
char* trim(char* input) {
char* start = input;
while (isSpace(*start)) { //trim left
start++;
}
char* ptr = start;
char* end = start;
while (*ptr++ != '\0') { //trim right
if (!isSpace(*ptr)) { //only move end pointer if char isn't a space
end = ptr;
}
}
*end = '\0'; //terminate the trimmed string with a null
return start;
}
bool isSpace(char c) {
switch (c) {
case ' ':
case '\n':
case '\t':
case '\f':
case '\r':
return true;
break;
default:
return false;
break;
}
}
【讨论】:
void inPlaceStrTrim(char* str) {
int k = 0;
int i = 0;
for (i=0; str[i] != '\0';) {
if (isspace(str[i])) {
// we have got a space...
k = i;
for (int j=i; j<strlen(str)-1; j++) {
str[j] = str[j+1];
}
str[strlen(str)-1] = '\0';
i = k; // start the loop again where we ended..
} else {
i++;
}
}
}
【讨论】:
这让我想自己写 - 我不喜欢提供的那些。在我看来应该有 3 个功能。
char *ltrim(char *s)
{
while(isspace(*s)) s++;
return s;
}
char *rtrim(char *s)
{
char* back = s + strlen(s);
while(isspace(*--back));
*(back+1) = '\0';
return s;
}
char *trim(char *s)
{
return rtrim(ltrim(s));
}
【讨论】:
ltrim 返回一个不适合传递给free 的指针。如果你使用它(或者,当然,trim),请确保你抓住了原始指针——尤其是在没有将s 存储在其他地方之前,不要尝试像s = trim(s); 这样的东西。
很惊讶看到这样的实现。我通常这样修剪:
char *trim(char *s) {
char *ptr;
if (!s)
return NULL; // handle NULL string
if (!*s)
return s; // handle empty string
for (ptr = s + strlen(s) - 1; (ptr >= s) && isspace(*ptr); --ptr);
ptr[1] = '\0';
return s;
}
它快速可靠 - 为我服务多年。
【讨论】:
您可以使用 ctype.h 中的标准 isspace() 函数来实现此目的。只需比较字符数组的开始和结束字符,直到两端不再有空格。
“空格”包括:
''(0x20)空间(SPC)
'\t' (0x09) 水平制表符 (TAB)
'\n' (0x0a) 换行符 (LF)
'\v' (0x0b) 垂直制表符 (VT)
'\f' (0x0c) 提要 (FF)
'\r' (0x0d) 回车(CR)
虽然没有可以为您完成所有工作的函数,但您必须推出自己的解决方案来反复比较给定字符数组的每一侧,直到没有空格。
编辑:
由于您可以使用 C++,Boost 有 a trim implementation 等着您,让您的生活更轻松。
【讨论】:
最简单的事情就是一个简单的循环。我将假设您希望将修剪后的字符串返回到位。
char *
strTrim(char * s){
int ix, jx;
int len ;
char * buf
len = strlen(s); /* possibly should use strnlen */
buf = (char *) malloc(strlen(s)+1);
for(ix=0, jx=0; ix < len; ix++){
if(!isspace(s[ix]))
buf[jx++] = s[ix];
buf[jx] = '\0';
strncpy(s, buf, jx); /* always looks as far as the null, but who cares? */
free(buf); /* no good leak goes unpunished */
return s; /* modifies s in place *and* returns it for swank */
}
这也消除了嵌入的空白,如果 String.Trim 没有,那么它需要更多的逻辑。
【讨论】:
没有标准的库函数可以做到这一点,但自己动手并不难。 SO上有一个existing question关于这样做,并用源代码回答。
【讨论】: