一次传递多个空格替换为单个空格并消除前导和尾随空格

时间:2010-03-16 15:19:50

标签: c whitespace

void RemoveSpace(char *String)
{
    int i=0,y=0;
    int leading=0;

    for(i=0,y=0;String[i]!='\0';i++,y++)
    {
        String[y]=String[i];    // let us copy the current character.

        if(isspace(String[i]))  // Is the current character a space?
        {
            if(isspace(String[i+1])||String[i+1]=='\0'||leading!=1) // leading space
                y--;
        }
        else
            leading=1;
    }
    String[y]='\0';
}

这是否可以删除前导空格和尾随空格并用单个空格替换多个空格? 我测试了它的空字符串,所有空格,前导空格和尾随空格。

您认为这是一种有效的一次通过解决方案吗?

5 个答案:

答案 0 :(得分:0)

根据您的代码,假设您的iswhite()效率很高, (你可能不会把它分开,因为它太频繁了) 假设传入的字符串本身是有效的(应该更具防御性)

=======================

void RemoveSpace(char *String)
{

    int i=0, j=0;

    int inWhite=0;

    char c = String[i++];
    while(c)
    {
        if (isspace(c))
        {
            inWhite= 1;
        }
        else
        {
            // there are space before, and not beginning
            if (inWhite && j > 0)
            {
                String[j++] = ' ';
            }
            String[j++] = c;
            inWhite = 0;
        }

        c = String[i++];
    }
    String[j]='\0';
}

未经测试,请自行测试......

答案 1 :(得分:0)

以下代码应该这样做:

void rem_space(char *str)
{
    int len = strlen(str) - 1;
    int i = 0;
    int spaces = 0;

    if(str == NULL) return;
    while(i < len){
        while(str[i] == ' ') {spaces++; i++;}
        while(str[i] != ' ' && str[i] != '\0') {str[i - spaces] = str[i]; i++;}
        if(str[i + spaces - 1] != '\0') {
            str[i - spaces] = ' '; spaces--; 
        } else {
            break;
        }
    }
    str[i - spaces] = '\0';
    return;
}

答案 2 :(得分:0)

  

这是否可以解决前导和尾随空格并用单个空格替换多个空格?

回答这个问题的最好方法是测试它。

void Test(const char *input, const char *expected_output) {
    char buffer[80];
    strcpy(buffer, input);
    RemoveSpace(buffer);
    assert(strcmp(buffer, expected_output) == 0);
}

int main() {
    Test("   Leading spaces removed.", "Leading spaces removed.");
    Test("Trailing spaces removed.  ", "Trailing spaces removed.");
    Test("Inner spaces      trimmed.", "Inner spaces trimmed.");
    Test(" A   little of  everything.  ", "A little of everything.");
    Test(" \tTabs \t\tare  \t spaces, too.", "Tabs are spaces, too.");
    return 0;
}

OP中的代码未通过最后一次测试,因此答案为

  

您认为这是一种有效的一次性解决方案吗?

这是一次性解决方案。如果你试图挤出每一盎司的效率,那么你想要最小化操作和条件分支的数量。

在C语言中使用C字符串时,使用指针而不是索引通常最惯用。根据编译器和目标平台,使用指针可能比索引更高效或更低效,但两者都是非常低的成本。由于这已经是单个线性传递,因此最好的做法是尽可能清晰地使用惯用代码模式进行编写。

这是我的解决方案:

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

void RemoveSpace(char *string) {
    char *target = string;
    char *last = target;
    int skipping_spaces = 1;

    for (const char *source = string; *source != '\0'; ++source) {
        if (isspace(*source)) {
            if (!skipping_spaces) {
                *target++ = *source;
                skipping_spaces = 1;
            }
        } else {
            *target++ = *source;
            last = target;
            skipping_spaces = 0;
        }
    }
    *last = '\0';
}

它本质上是一个小状态机,这意味着,在每一步,我们根据当前输入字符和当前状态决定做什么。对于这个问题,我们的状态就是我们当前是否正在跳过空格(以及一个跟踪最后一个合法点以结束字符串的书签)。

答案 3 :(得分:0)

首先,显然,这是一次通过。但是,当输入具有多个前导空格时,它会出现问题。例如:

输入:" text"输出:" text"

幸运的是,它很容易解决。你只需要一个额外的循环:

void RemoveSpace(char *string)
{
        int i = 0, y = 0;
        while(isspace(string[i]))         // Discard leading spaces.
                i++;
        for(y = 0; string[i]!='\0'; i++)
        {
                string[y] = string[i];    // let us copy the current character.

                if(!isspace(string[i]) || !isspace(string[i+1]) && !string[i+1]=='\0')
                        y++;              // This character shall not be covered.
        }
        string[y] = '\0';
}

我也进行了一些更改,以使您的代码看起来更好,这实际上是无关紧要的。

答案 4 :(得分:0)

'''

python ... 3.x

导入操作符 ...

行:文本行

返回“” .join(filter(lambda a:operator.is_not(a,“”), line .strip()。split(“”))) '''