在C语言中如何截取字符串

29
简要说明:
我想找到C语言中使用win32和标准C API的等效于.NET的String.Trim的方法(使用MSVC2008编译,因此如果需要,可以访问所有C++内容,但我只是尝试修剪一个char*)。
鉴于存在strchrstrtok和各种其他字符串函数,肯定有一个修剪函数,或者可以重新用途的函数...
谢谢
15个回答

0
/* 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;
}

-1
这样怎么样?它只需要对字符串进行一次迭代(不使用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;
    }
}

这会直接修改输入的字符串。虽然看起来性能很好,但除非绝对必要,否则我不会使用它,因为直接修改字符串可能是意外的,而返回到现有字符串中间的起始指针也是如此。调用者必须知道在“修剪”后的字符串不再需要之前不要删除原始字符串。 - Orion Edwards

-2

虽然不是最好的方法,但它能够工作

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

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

哎呀,那很糟糕。看起来它也会删除内部空格? " foo bar " 应该被修剪为 "foo bar",而不是 "foobar"。 - Orion Edwards
即使操作要求将内部也修剪,此代码仍非常冗余。糟糕! - pqsk

-6
最简单的方法是使用一个简单的循环。我假设你想要在原地返回修剪过的字符串。
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无法去除嵌入的空格,则需要更多的逻辑来解决这个问题。


如果你malloc一个新的缓冲区,然后将其复制回去,那么这几乎不是“原地修改”! - Andrew Grant
@Andrew,我不去面试,我是面试官。@qrdl,那你会有一个以\0开头的字符数组。在C语言中,这被称为“零长度字符串”。 - Charlie Martin
啊,这很简单。这是唯一的构建方式,它不会受到缓冲区大小的影响,特别是不会对输入施加长度限制,可以在单次通过中完成,并且不会返回malloc分配的内存。 - Charlie Martin
3
malloc防止一个原地函数对输入大小敏感吗?抱歉,那是不正确的。调用两次strlen也让你失去了单遍传递的参数。尽管较慢且较长,但您的函数实际上并没有起作用 - 什么时候修剪函数会删除单词之间的空格呢? - Andrew Grant
你将字符串的长度保存到 len 变量中(这是错误类型的变量,应该是 size_t 类型),但是你没有使用 len 进行动态内存分配,而是再次调用了 strlen。你还建议使用非标准函数 strnlen。它会删除 "嵌入的空格"?!你还有一个语法错误(你的 for 循环缺少闭合括号)。你将 malloc 的返回值强制转换,并且甚至没有检查是否为 NULL - dreamlax
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接