C语言 消除字符串中的所有多余空格

ahy6op9u  于 2023-05-16  发布在  其他
关注(0)|答案(2)|浏览(159)

函数必须消除单词和标点符号之间的所有额外空格,但标点符号与前面的单词之间不得有任何空格。
例如,我有这个字符串:

Hey   ,how   are you today    ?

我应该得到这个:

Hey, how are you today?

这个函数消除了这里的多余空间。但我不知道怎么把标点符号写进去
顺便说一句,我正在主函数中调用这个函数

void space_rule(char *str[]){
printf("Enter a string: ");
gets(*str);
puts(*str);

char *p = strtok(*str, " ");
    while(*p!=NULL){
    printf("%s ",p);
    p=strtok(NULL, " ");
}

}
neekobn8

neekobn81#

考虑:

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

int main()
{
    const char* input = "Hey   ,how   are you today    ?" ;
    const char* chp = input ;
    
    // While not end of input...
    while( *chp != '\0' )
    {
        
        // Print all regular characters (not space or punctuation)
        if( !(isspace( *chp ) || ispunct( *chp )) )
        {
            putchar( *chp ) ;
            chp++ ;
        }
        // Print all punctuation followed by a space (except at end)
        else if( ispunct( *chp ) )
        {
            putchar( *chp ) ;
            chp++ ;
            if( *chp != '\0' && !isspace( *chp ) )
            {
                putchar( ' ' ) ;
            }
        }
        // Is space...
        else if( isspace( *chp ) )
        {
            // Skip all space
            while( *chp != '\0' && isspace( *chp ) )
            {
                chp++ ;
            }
            
            // If not end, and not punctuation...
            if( *chp != '\0' && !ispunct( *chp ) )
            {
                // ...insert single space 
                putchar( ' ' ) ;
            }
        }
    }
    
    return 0;
}

但是,您可能需要更仔细地细化规则。也许不是所有的标点符号都应该被同样对待?例如:

const char* input = "She said \"Hello\"" ;

输出为:

She said" Hello"

这不太可能是有意的。为此,您不仅需要包含'"'的例外规则,还需要考虑开盘和收盘报价并相应地应用规则。给读者的一个练习--如果你仍然被这个问题卡住了,我建议你发布一个新的问题。
如果你有一个像这样的字符串,它会变得非常复杂:

She said, "Hey, how are, you today?"

因为你有?",对于?你需要一个规则:“* 除非下一个字符也是标点符号,否则标点符号后要有空格 *"。但是如果?"被空格隔开,你必须在做出决定之前首先消除它。老实说,我放弃了试图弄清楚所有的排列。我建议,如果你想这样做,你可以在多个通道中执行变换,一次应用一个规则,例如:
1.将所有多个空格减少为1个空格
1.如果标点符号后面没有空格,并且不是一个开始引号('"),则在标点符号后面插入空格。
1.删除标点符号之间的空格
1.如果没有空格,请在 * 开始引号前插入空格 *。
通过更简单的规则(在单独的函数中执行)和多个通道,以牺牲效率为代价将更容易获得正确的结果。然后,您还可以轻松地重新排序规则的应用程序,以获得预期的结果。例如,规则4必须在规则3之后应用。

6kkfgxo0

6kkfgxo02#

您想要的更改都可以表示为基于每对相邻字符的类型的更改。您需要将每个字符描述为空格、字母或标点符号,并按如下方式处理字符对:

  • :删除一个(第一个?)空间
  • :删除空格
  • :在它们之间插入空格
  • 否则:别管它。

由于这些配对规则从不对配对中的第二个字符做任何事情,因此建议使用一个简单的循环,将字符从输入缓冲区复制到输出缓冲区,并在执行时进行这些更改:

void copy_and_fix(char *out, const char *in) {
    while (*in) {
        if (isspace(in[0]) && isspace(in[1])) {
            // don't copy the first space
        } else if (isspace(in[0]) && ispunct(in[1])) {
            // don't copy the space
        } else if (ispunct(in[0]) && iswordchar(in[1])) {
            // keep the punct and insert a space;
            *out++ = *in;
            *out++ = ' ';
        } else {
            // just copy the character
            *out++ = *in;
        }
        ++in;
    }
    *out = '\0';  // NUL terminate the output.
}

当然,你需要小心缓冲区的大小,以确保你不会溢出输出缓冲区,但这可以用各种方法来处理(确保输出缓冲区至少是输入大小的1.5,或者传递一个大小并在必要时截断输出,或者在堆上分配输出缓冲区并根据需要调整大小)。

相关问题