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

Mimic Python's strip() function in C

我最近开始用C编写一个小玩具项目,一直在努力模仿python字符串对象一部分的strip()功能的最佳方法。

读一遍fscanf或sscanf表示该字符串被处理到遇到的第一个空格。

fgets也无济于事,因为我仍然有换行符。
我确实尝试了strchr()来搜索空格,并将返回的指针显式设置为" 0",但这似乎不起作用。


Python字符串的strip方法将删除尾部和前导空格。当使用C"字符串"(字符数组, 0终止)时,问题的两半非常不同。

对于尾随空格:将指针(或等效索引)设置为现有尾随 0。不断递减指针,直到指针碰到字符串开头或任何非白色字符为止;将 0设置在此终止向后扫描点之后的右边。

对于前导空格:将指针(或等效索引)设置为字符串的开头;不断增加指针,直到它碰到非白色字符(可能跟在 0后面);记住字符串的其余部分,以便第一个非白色的字符串到达??字符串的开头(类似地,随后的所有内容)。


对于strip()或trim()函数,没有标准的C实现。就是说,这是Linux内核中包含的一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}


我编写了C代码来实现此功能。我还编写了一些琐碎的测试,以确保我的函数执行明智的操作。

该函数将写入您提供的缓冲区,并且永远都不应写入缓冲区的末尾,因此它不容易出现缓冲区溢出安全性问题。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// 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)
"
, s, buf, len);
}


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

如果要删除一行中的最后一个换行符,可以使用以下代码段:

1
2
3
size_t s = strlen(buf);
if (s && (buf[s-1] == '
'
)) buf[--s] = 0;

为了忠实地模仿Python的str.strip([chars])方法(我解释其工作方式的方式),您需要为新字符串分配空间,填充新字符串并返回它。之后,当您不再需要剥离的字符串时,需要释放以前没有内存泄漏的内存。

或者,您可以使用C指针并修改初始字符串并获得类似的结果。
假设您的初始字符串为"____forty two____
"
,并且您要去除所有下划线和' n'

1
2
3
____forty two___

^ ptr

如果将ptr更改为'f'并将two之后的第一个'_'替换为'\0',则结果与Python的"____forty two____
".strip("_
");
相同

1
2
3
____forty two\0___

    ^ptr

同样,这与Python不同。该字符串已在适当位置修改,没有第二个字符串,并且您无法还原更改(原始字符串丢失)。