如何用C字符串中的单个空格替换空格的跨度?

时间:2017-03-23 03:43:45

标签: c

我正在尝试编写一个函数,将空格的所有跨度(即多个空格,换行符,制表符或上述任何连续序列)转换为单个空格。

例如,以下输入:

!541

都会产生相同的输出:     “示例输入字符串”

我目前在Stack Overflow上有类似问题的代码如下(https://stackoverflow.com/a/1217750/6652030,第二个答案)。它正确处理多个空格的序列,但它不会按预期用空格替换制表符和换行符。如果我传递前两个示例输入,我的结果字符串是“exampleinputstring”。关于我哪里出错的任何想法?

"example\tinput\tstring"
"example\ninput\nstring"
"example  \tinput \n string"

4 个答案:

答案 0 :(得分:1)

您可以对代码进行以下修改:

void removeExtraWhitespace(char *dst, const char *src) {
  for(; *src; ++dst, ++src) {
    if (isspace(*src)) {
      *dst = ' ';
      while (isspace(*(src + 1))) {
        ++src;
      }
    } else {
      *dst = *src;
    }
  }
  *dst = '\0';
}

例如,

char dst[50];
$ removeExtraWhitespace(dst, "\t\t\texample\t\t\n    input\nstring\n\n   ");
$ printf("%s\n", dst);
 example input string 

答案 1 :(得分:0)

本质上,您将字符串复制到新位置,同时将所有空格(和换行符)字符折叠为单个字符(如果我理解正确的话)。

在复制时,您有三种可能的“操作模式”:

  1. 没有空白(直接复制)
  2. “空白”模式 - 您遇到了一个空格字符,目前正在跳过,直到您再次看到非空格
  3. 您已完成跳过空格并返回“直接复制”模式
  4. 将其置于伪代码中,如下所示:

    bool skipping = false;
    for(each char){
      if(iswhite(char)){
        skipping = true;
        continue; // next source char
      }
      // not a whitespace, let's see if we are done skipping
      if(skipping){
        // collapse all those skipped whitespaces into one
        copy_space_into_dest;
      }
      skipping = false;
      copy_char_into_dest;
    }
    

    上面的iswhite()可能是对isspace()或您自己的函数的调用,该函数将返回true以查看它认为是空格的任何内容(例如,如果您确定为{ {1}}是一个“白色空间”)

答案 2 :(得分:0)

我提出的问题代码是:

static
void removeExtraWhiteSpace(char *src, char *dst)
{
    while (*src != '\0')
    {
        if (!isspace((unsigned char)*src))
            *dst++ = *src++;
        else
        {
            *dst++ = ' ';
            while (isspace((unsigned char)*src))
                src++;
        }
    }
    *dst = '\0';
}

对于每个字符,如果它不是来自isspace()的{​​{1}}的空格,请将其复制到输出中。如果是空格,请将空格复制到输出,并跳过任何后续空格字符。完成后,添加null终止符。

函数是<ctype.h>,因为我创建了所有函数static,除非有一个标题声明函数用于其他文件 - 我使用的编译选项需要这个规则(或者先验static函数声明 - 但extern void removeExtraWhiteSpace(char *src, char *dst)更短。

如果你想删除前导和尾随空白,那就不难了:

static

测试代码:

static
void removeExtraWhiteSpace(char *src, char *dst)
{
    char *tgt = dst;
    while (isspace((unsigned char)*src))
        src++;
    while (*src != '\0')
    {
        if (!isspace((unsigned char)*src))
            *tgt++ = *src++;
        else
        {
            *tgt++ = ' ';
            while (isspace((unsigned char)*src))
                src++;
        }
    }
    *tgt = '\0';
    if (tgt > dst && tgt[-1] == ' ')
        tgt[-1] = '\0';
}

平原输出:

static void test_string(char *buffer1)
{
    printf("Before [%s]\n", buffer1);
    char buffer2[1024];
    removeExtraWhiteSpace(buffer1, buffer2);
    printf("After  [%s]\n", buffer2);
}

int main(void)
{
    test_string("example\tinput\tstring");
    test_string("example\ninput\nstring");
    test_string("example  \tinput \n string");
    test_string("  \t spaces\t \tand tabs\tboth  before\t\tand  \t \t after  \t\t ");

#ifdef GO_INTERACTIVE
    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        buffer[strcspn(buffer, "\n")] = '\0';
        test_string(buffer);
    }
#endif /* GO_INTERACTIVE */

    return 0;
}

标记了标签和换行符(^ I表示标签,^ J表示换行符):

Before [example input   string]
After  [example input string]
Before [example
input
string]
After  [example input string]
Before [example     input 
 string]
After  [example input string]
Before [     spaces     and tabs    both  before        and          after           ]
After  [ spaces and tabs both before and after ]

答案 3 :(得分:0)

  

如何用C字符串中的单个空格替换空格的跨度?

只需跟踪上一个操作并测试空格。只需要1个紧密循环,一次调用package models; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); public static SessionFactory buildSessionFactory(){ try{ // Create the SessionFactory from hibernate.cfg.xml System.out.println("creating SessionFactory using HibernateUtil.java"); SessionFactory f = new Configuration().configure().buildSessionFactory(); System.out.println("session created successfully"); return f; } catch (Throwable ex){ // Make sure you log the exception, as it might be swallowed System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } } 。这也处理前导/尾随空格。

isspace()
  

关于我哪里出错的任何想法?

当OP的代码第一次遇到#include <ctype.h> #include <stdbool.h> void removeExtraWhitespace(const char *src, char *dst) { bool previous_was_whitespace = false; while (*src) { if (isspace((unsigned char) *src)) { if (!previous_was_whitespace) { *dst++ = ' '; } previous_was_whitespace = true; } else { *dst++ = *src; previous_was_whitespace = false; } src++; } *dst = '\0'; } '\n'时,它会更改'\t',但永远不会影响src[]

同时删除以下代码中的dst[]。这允许在else'\n'之后消耗连续的空格。然而,这仍然存在其他空白区域的问题,例如'\t'

'\r'

此代码使用if (*src == '\n' || *src == '\t') { *src = ' '; } // else if (isspace(*src)) { if (isspace(*src)) { 而不是isspace((unsigned char) *src),因为isspace(*src)仅针对isspace()范围和unsigned char中的值定义。对于学习者计划,遇到EOF的负值是不常见的,但它们可以存在,并且转换到*src范围是谨慎的。