Один проход нескольких пробелов заменяет один пробел и устраняет начальные и конечные пробелы - PullRequest
3 голосов
/ 16 марта 2010
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';
}

Делает ли это трюк с удалением начальных и конечных пробелов и заменой нескольких пробелов на отдельные ?? я проверил его на наличие нулевой строки, всех пробелов, начальных пробелов и конечных пробелов.

Как вы думаете, это эффективное решение за один проход?

Ответы [ 4 ]

0 голосов
/ 16 февраля 2016

Во-первых, очевидно, это один проход. Тем не менее, он имеет проблему, когда ввод имеет более одного пробела. Например:

Вход: " 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';
}

Я также внес некоторые изменения, чтобы ваш код выглядел лучше, что на самом деле не имеет значения.

0 голосов
/ 23 марта 2011

Следующий код должен сделать это:

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;
}
0 голосов
/ 16 февраля 2016

Делает ли это трюк с удалением начальных и конечных пробелов и заменой нескольких пробелов на одиночные?

Лучший способ ответить на этот вопрос - проверить его.

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

По сути, это маленький конечный автомат, что означает, что на каждом шаге мы решаем, что делать, основываясь на текущем вводимом символе и текущем состоянии. Для этой проблемы наше государство просто: пропускаем ли мы пробелы в данный момент (и закладку, отслеживающую последнюю юридическую точку, заканчивающую строку).

0 голосов
/ 16 марта 2010

на основе вашего кода, предположим, что ваш 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';
}

не проверено, пожалуйста, проверьте себя ...

...