在C语言中模仿Python的strip()函数

7
我最近开始在C语言上做一个小玩具项目,一直在考虑如何最好地模拟Python字符串对象中的strip()功能。根据对fscanf或sscanf的阅读,它们只会处理遇到的第一个空格之前的字符串。fgets也无法解决问题,因为仍然会有换行符存在。我尝试使用strchr()搜索空格并将返回的指针显式设置为'\0',但这似乎不起作用。请帮我解决这个问题。
5个回答

14

Python字符串的strip方法可以同时删除字符串前后的空格。然而,当处理C语言中的“字符串”(即以\0结束的字符数组)时,这个问题有两个非常不同的方面。

针对尾部空格:将指针(或等效的索引)设置为现有的结尾\0。反复减小指针直到它停留在字符串开头或任何非空白字符上;然后将\0设置在此向后终止扫描点之后。

针对首部空格:将指针(或等效的索引)设置为字符串的开头;反复增加指针直到它遇到一个非空白字符(可能是结尾的\0);使用memmove函数将其余的字符串移动,使得第一个非空白字符移到字符串开头(对于其后的所有内容也是如此)。


似乎很合理。你使用memmove()而不是strncpy(),因为Python字符串是缓冲区,可能包含'\0'字符? - Matt Joiner
@Matt 确切地说:一个尾随的\0是有保证的,但在Python字节字符串内部可能还有其他字符。 - Alex Martelli
将剩余的字符串memmove,以便第一个非空格字符位于字符串开头(对于其后的所有内容也是如此)。请注意,如果将C中的“strip()”方法传递给字符串字面值,则不能保证其有效。实际上,这可能会导致内存访问冲突,具体取决于操作系统。 - Andrew Henle

12

目前没有标准的C语言实现strip()或trim()函数。 但是,下面是Linux内核中包含的一个实现:

char *strstrip(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';

        while (*s && isspace(*s))
                s++;

        return s;
}

13
当然,要使用这里提供的代码,项目必须使用GPLv2或之前版本,因为Linux内核使用的就是这个版本。 - Powerlord
1
太好了,这看起来完美无缺。谢谢 :) - sudharsh

1
如果您想要在原地删除一行的最后一个换行符,可以使用以下代码片段:
size_t s = strlen(buf);
if (s && (buf[s-1] == '\n')) buf[--s] = 0;

为了忠实地模仿Python的str.strip([chars])方法(我理解的方式),您需要为新字符串分配空间,填充新字符串并返回它。之后,当您不再需要剥离的字符串时,您需要释放它所使用的内存以避免内存泄漏。
或者,您可以使用C指针修改初始字符串并实现类似的结果。
假设您的初始字符串是"____forty two____\n",您想要剥离所有下划线和'\n'
____forty two___\n
^ ptr

如果你将ptr改为'f',并将two后面的第一个下划线替换为'\0',结果与Python的"____forty two____\n".strip("_\n");相同。
____forty two\0___\n
    ^ptr

再次强调,这与Python不同。字符串是就地修改的,没有第二个字符串,也无法撤销更改(原始字符串丢失)。


1

我编写了C代码来实现这个函数。我还编写了一些微不足道的测试,以确保我的函数执行合理的操作。

此函数将写入您提供的缓冲区,并且不应在缓冲区末尾之后写入,因此不应容易受到缓冲区溢出安全问题的影响。

注意:只有Test()使用stdio.h,因此如果您只需要该函数,则只需包含ctype.h(用于isspace())和string.h(用于strlen())。

// strstrip.c -- implement white space stripping for a string in C
//
// This code is released into the public domain.
//
// You may use it for any purpose whatsoever, and you don't need to advertise
// where you got it, but you aren't allowed to sue me for giving you free
// code; all the risk of using this is yours.



#include <ctype.h>
#include <stdio.h>
#include <string.h>



// strstrip() -- strip leading and trailing white space from a string
//
// Copies from sIn to sOut, writing at most lenOut characters.
//
// Returns number of characters in returned string, or -1 on an error.
// If you get -1 back, then nothing was written to sOut at all.

int
strstrip(char *sOut, unsigned int lenOut, char const *sIn)
{
    char const *pStart, *pEnd;
    unsigned int len;
    char *pOut;

    // if there is no room for any output, or a null pointer, return error!
    if (0 == lenOut || !sIn || !sOut)
        return -1;

    pStart = sIn;
    pEnd = sIn + strlen(sIn) - 1;

    // skip any leading whitespace
    while (*pStart && isspace(*pStart))
        ++pStart;

    // skip any trailing whitespace
    while (pEnd >= sIn && isspace(*pEnd))
        --pEnd;

    pOut = sOut;
    len = 0;

    // copy into output buffer
    while (pStart <= pEnd && len < lenOut - 1)
    {
        *pOut++ = *pStart++;
        ++len;
    }


    // ensure output buffer is properly terminated
    *pOut = '\0';
    return len;
}


void
Test(const char *s)
{
    int len;
    char buf[1024];

    len = strstrip(buf, sizeof(buf), s);

    if (!s)
        s = "**null**";  // don't ask printf to print a null string
    if (-1 == len)
        *buf = '\0';  // don't ask printf to print garbage from buf

    printf("Input: \"%s\"  Result: \"%s\" (%d chars)\n", s, buf, len);
}


main()
{
    Test(NULL);
    Test("");
    Test(" ");
    Test("    ");
    Test("x");
    Test("  x");
    Test("  x   ");
    Test("  x y z   ");
    Test("x y z");
}

0

这个潜在的“解决方案”绝不像其他人呈现的那样完整或彻底。这是为了我自己的C语言玩具项目 - 一个我正在与我14岁的儿子一起开发的基于文本的冒险游戏。如果您正在使用fgets(),那么strcspn()也可能适用于您。下面的示例代码是交互式控制台循环的开始。

#include <stdio.h>
#include <string.h> // for strcspn()

int main(void)
{
    char input[64];
    puts("Press <q> to exit..");
    do {
        
        printf("> ");
        fgets(input,64,stdin); // fgets() captures '\n'
        input[strcspn(input, "\n")] = 0; // replaces '\n' with 0 
        if (input[0] == '\0') continue; 
        printf("You entered '%s'\n", input);
        
    } while (strcmp(input,"q")!= 0); // returns 0 (false) when input = "q"

    puts("Goodbye!");
    return 0;
}

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