Удалить лишние пробелы внутри строки C? - PullRequest
4 голосов
/ 22 сентября 2009

Я прочитал несколько строк текста в массив C-строк. Строки имеют произвольное количество столбцов с табуляцией или пробелами, и я пытаюсь выяснить, как удалить все лишние пробелы между ними. Конечная цель - использовать strtok, чтобы разбить столбцы. Это хороший пример столбцов:

Cartwright   Wendy    93
Williamson   Mark     81
Thompson     Mark     100
Anderson     John     76
Turner       Dennis   56

Как я могу устранить все пробелы или табуляции между столбцами, кроме одного, чтобы выходные данные выглядели так?

Cartwright Wendy 93

Или же я могу просто заменить все пробелы между столбцами другим символом, чтобы использовать strtok? Как то так?

Cartwright#Wendy#93

edit: Несколько отличных ответов, но пришлось выбрать один. Спасибо всем за помощь.

Ответы [ 9 ]

11 голосов
/ 22 сентября 2009

Если я могу высказать мнение «вы делаете это неправильно», почему бы просто не устранить пробелы во время чтения? Используйте fscanf("%s", string);, чтобы прочитать «слово» (без пробелов), затем прочитайте пробел. Если это пробелы или табуляции, продолжайте читать в одну «строку» данных. Если это новая строка, начните новую запись. Вероятно, в C проще всего получить данные в формате, с которым вы можете работать, как можно скорее, вместо того, чтобы пытаться выполнять тяжелые операции с текстом.

5 голосов
/ 22 сентября 2009

Почему бы не использовать strtok() напрямую? Нет необходимости изменять ввод

Все, что вам нужно сделать, это повторять strtok(), пока вы не получите 3 жетона без пробелов, и тогда все готово!

2 голосов
/ 22 сентября 2009

Следующий код изменяет строку на месте; если вы не хотите уничтожать исходный ввод, вы можете передать второй буфер для получения измененной строки. Должно быть достаточно понятным:

#include <stdio.h>
#include <string.h>

char *squeeze(char *str)
{
  int r; /* next character to be read */
  int w; /* next character to be written */

  r=w=0;
  while (str[r])
  {
    if (isspace(str[r]) || iscntrl(str[r]))
    {
      if (w > 0 && !isspace(str[w-1]))
        str[w++] = ' ';
    }
    else
      str[w++] = str[r];
    r++;
  }
  str[w] = 0;
  return str;
}

int main(void)
{
  char test[] = "\t\nThis\nis\ta\b     test.";
  printf("test = %s\n", test);
  printf("squeeze(test) = %s\n", squeeze(test));
  return 0;
}
2 голосов
/ 22 сентября 2009

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

void squeezespaces(char* row, char separator) {
  char *current = row;
  int spacing = 0;
  int i;

  for(i=0; row[i]; ++i) {
    if(row[i]==' ') {
      if (!spacing) {
        /* start of a run of spaces -> separator */
        *current++ = separator
        spacing = 1;
      }
    } else {
      *current++ = row[i];
      spacing = 0;
  }
  *current = 0;    
}
1 голос
/ 24 августа 2012
char* trimwhitespace(char *str_base) {
    char* buffer = str_base;
    while((buffer = strchr(str_base, ' '))) {
        strcpy(buffer, buffer+1);
    }

    return str_base;
}
0 голосов
/ 05 октября 2016

Следующий код просто принимает вводимые символы, а затем проверяет для каждого символа, есть ли место больше, чем когда он пропускает его, иначе он печатает символ. Та же логика, которую вы можете использовать для вкладки также. Надеюсь, это поможет в решении вашей проблемы. Если есть какие-либо проблемы с этим кодом, пожалуйста, дайте мне знать.

    int c, count = 0;
    printf ("Please enter your sentence\n");
    while ( ( c = getchar() ) != EOF )  {
        if ( c != ' ' )  {
            putchar ( c );
            count = 0;
        }
        else  {
            count ++;
            if ( count > 1 )
                ;    /* Empty if body */
            else
                putchar ( c );
         }
     }
}
0 голосов
/ 04 февраля 2014

Я сделал небольшое улучшение над Джоном Боде, чтобы удалить также пробел:

#include <ctype.h>

char *squeeze(char *str)
{
  char* r; /* next character to be read */
  char* w; /* next character to be written */
  char c;
  int sp, sp_old = 0;

  r=w=str;

  do {
    c=*r;
    sp = isspace(c);
    if (!sp) {
      if (sp_old && c) {
        // don't add a space at end of string
        *w++ = ' ';
      }
      *w++ = c;
    }
    if (str < w) {
      // don't add space at start of line
      sp_old = sp;
    }
    r++;
  }
  while (c);

  return str;
}

#include <stdio.h>

int main(void)
{
  char test[] = "\t\nThis\nis\ta\f     test.\n\t\n";
  //printf("test = %s\n", test);
  printf("squeeze(test) = '%s'\n", squeeze(test));
  return 0;
}

шир.

0 голосов
/ 22 сентября 2009

Вот альтернативная функция, которая выжимает повторяющиеся пробелы, как определено isspace() в <ctype.h>. Возвращает длину строки squidged.

#include <ctype.h>

size_t squidge(char *str)
{
    char *dst = str;
    char *src = str;
    char  c;
    while ((c = *src++) != '\0')
    {
        if (isspace(c))
        {
            *dst++ = ' ';
            while ((c = *src++) != '\0' && isspace(c))
                ;
            if (c == '\0')
                break;
        }
        *dst++ = c;
    }
    *dst = '\0';
    return(dst - str);
}

#include <stdio.h>
#include <string.h>

int main(void)
{
    char buffer[256];
    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        size_t len = strlen(buffer);
        if (len > 0)
            buffer[--len] = '\0';
        printf("Before: %zd <<%s>>\n", len, buffer);
        len = squidge(buffer);
        printf("After:  %zd <<%s>>\n", len, buffer);
    }
    return(0);
}
0 голосов
/ 22 сентября 2009

Вы можете прочитать строку и отсканировать ее, чтобы найти начало каждого столбца. Затем используйте данные столбца по своему усмотрению.

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

#define MAX_COL 3
#define MAX_REC 512

int main (void)
{
    FILE *input;
    char record[MAX_REC + 1];
    char *scan;
    const char *recEnd;
    char *columns[MAX_COL] = { 0 };
    int colCnt;

    input = fopen("input.txt", "r");

    while (fgets(record, sizeof(record), input) != NULL)
    {
        memset(columns, 0, sizeof(columns));  // reset column start pointers

        scan = record;
        recEnd = record + strlen(record);

        for (colCnt = 0; colCnt < MAX_COL; colCnt++ )
        {
          while (scan < recEnd && isspace(*scan)) { scan++; }  // bypass whitespace
          if (scan == recEnd) { break; }
          columns[colCnt] = scan;  // save column start
          while (scan < recEnd && !isspace(*scan)) { scan++; }  // bypass column word
          *scan++ = '\0';
        }

        if (colCnt > 0)
        {
            printf("%s", columns[0]);
            for (int i = 1; i < colCnt; i++)
            {
             printf("#%s", columns[i]);
            }
            printf("\n");
        }
    }

    fclose(input);
}

Обратите внимание, что в коде все еще может использоваться некоторая надежная индикация: проверка на наличие ошибок в файлах с помощью ferror; убедитесь, что еф был поражен; убедитесь, что вся запись (все данные столбца) была обработана. Это также можно сделать более гибким, используя связанный список вместо фиксированного массива, и его можно изменить, чтобы он не предполагал, что каждый столбец содержит только одно слово (если столбцы ограничены определенным символом).

...