用制表符替换空格

时间:2014-03-14 06:57:16

标签: c string replace

我刚刚完成了 The C Programming Language 的第一章,在继续之前还有一些练习。我已经完成了用空格替换制表符的那个,这很容易,但我坚持用一个用适当数量的制表符和空格替换空格字符来实现相同的间距。

我的实施"有时"工作,所以基本上它不起作用。这是功能:

#define TABLEN 5

// entab: replace consecutive spaces of length TABLEN with the tab character
void entab(char string[])
{
    int i, consec;
    int to, from, tabloc;

    consec = 0;
    for (i = 0; string[i] != '\0'; ++i) {
        // count consecutive spaces in a string
        if (string[i] == ' ') ++consec;
        else consec = 0;

        if (consec >= TABLEN) {
            // set location to insert tab character
            tabloc = (i - TABLEN) + 1;

            for (to = tabloc, from = i;
                string[from] != '\0'; ++from, ++to)
            {
                // replace space characters
                string[to] = string[from];
            }

            string[tabloc] = '\t';
            string[to] = '\0';
            i = tabloc;
            consec = 0;
        }
    }
}

这项功能在成功运作方面非常不一致,甚至连一种模式都没有效果。由于"没有工作",我的意思是两种情况中的一种。 1.)删除空格并且不插入制表符,或者2.)删除空格,插入制表符,但不知何故添加了额外的空格。这些问题让我意识到问题存在于取代空格的循环,但我对C这么新,我不知道出了什么问题。有人能指出我在正确的方向吗?

2 个答案:

答案 0 :(得分:3)

以下是标签的工作方式:

如果您输入

      Tab 
      v     v     v     v
 ------------------------
|     a
|a    a
|aa   a
|aaa  a
|aaaa a

注意如果有5个,4个,3个,2个或1个空格,它们都可以平均表示为制表符。这就是5个空格不等于标签的原因(即使标签大小设置为5)。考虑这种情况:

      v     v     v     v
 ------------------------
|aaaa     a
|    12345

但是当你用标签替换这5个空格时,你会得到:

      v     v     v     v
 ------------------------
|aaaa a
| 12345

这是一个有效的例子:

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

void Print_As_String(char * buffer, unsigned int size);
void Print_As_Hex(char * buffer, unsigned int size);

void Convert_Tab_To_Space(char * buffer, unsigned int size, unsigned int tab_size);

int main(unsigned int argc, char * argv[]){

  unsigned int i = 0;
  unsigned int arg_length = 0;

  if (argc <= 1){
    printf("Usage: \"Text with spaces\", \"More text with spaces\", etc\n");
    return -1;
  }

    for (i = 1; i < argc; i++){

      arg_length = strlen(argv[i]);

      Print_As_String (argv[i], arg_length);
      Print_As_Hex    (argv[i], arg_length);

      Convert_Tab_To_Space(argv[i], arg_length, 8);

      Print_As_String (argv[i], arg_length);
      Print_As_Hex    (argv[i], arg_length);
  }

  return 0;
}

void Print_As_String(char * buffer, unsigned int size){
  printf("%.*s\n", size, buffer);
}

void Print_As_Hex(char * buffer, unsigned int size){

  unsigned int i = 0;
  const char hex_table[16] = "0123456789ABCDEF";

  for (i = 0; i < size; i++){
    unsigned char high_byte = 0;
    unsigned char low_byte = 0;

    high_byte = (buffer[i] & 0xF0) >> 4;
    low_byte  = (buffer[i] & 0x0F) >> 0;

    putc(hex_table[high_byte], stdout);
    putc(hex_table[low_byte], stdout);
    putc(' ', stdout);
  }

  putc('\n', stdout);
}

void Shift_Characters_Left(char * buffer,
                       unsigned int position_start,
                       unsigned int position_end,
                       unsigned int size);

void Convert_Tab_To_Space(char * buffer, unsigned int size, unsigned int tab_size){

  unsigned int i = 0;
  unsigned int x = 0; /* x is used
        for getting the position in
        the current line. This is
        different from 'i' because
        there may be many lines in
        one string.
  */

  for (i = 0; i < size; i++){

    if (buffer[i] == '\t'){ /* the x coordinates
      change in this fashion when a new
      tab is found.
    */
      x += tab_size - (x % tab_size);

    } else if (buffer[i] == ' '){

      unsigned int tab_remainder = 0; // how many spots are left for a tab
      unsigned int space_i = 1; // space index

      tab_remainder = (x % tab_size);

      while ((i + space_i) < size){

        /* if the space count makes up for the
           missing spots in the tab remainder,
           replaces the spaces with a tab
        */

        if ((tab_remainder + space_i) == tab_size){
          Shift_Characters_Left(buffer,      // move the spot at the end of
                                i + space_i, // the spaces to the spot at
                                i + 1,       // the start of the spaces
                                size);
          buffer[i] = '\t';
        }

        if (buffer[i + space_i] != ' '){
          i += space_i;
          break;
        }

        space_i++;
      }

    } else if (buffer[i] == '\n'){
      x = 0;
    } else {
      x++;
    }
  }
}

void Shift_Characters_Left(char * buffer,
                       unsigned int position_start,
                       unsigned int position_end,
                       unsigned int size){
  memmove(buffer + position_end,
      buffer + position_start,
      size - position_end);
  memset(&buffer[position_start], 0, (size - 1) - position_start);
}

但是当我测试这个问题时,我得到了一个无法解决的错误。我认为这是{错误memset(可能是一个错误的错误)。

答案 1 :(得分:1)

以下工作正常。检查索引中的差异

#include <stdio.h>

#define TABLEN 5
// entab: replace consecutive spaces of length TABLEN with the tab character
void entab(char string[])
{
    int i, consec;
    int to, from, tabloc;
        printf("%s\n",string);

    consec = 0;
    for (i = 0; string[i] != '\0'; ++i) {
        // count consecutive spaces in a string
        if (string[i] == ' ') ++consec;
        else consec = 0;

        if (consec >= TABLEN) {
            // set location to insert tab character
            tabloc = (i - TABLEN) + 1;

            for (to = tabloc+1, from = i+1;
                 string[from] != '\0'; ++from, ++to)
            {
                // replace space characters
                string[to] = string[from];
            }

            string[tabloc] = '\t';
            string[to] = '\0';
            i = tabloc+1;
            consec = 0;
        }
    }
    printf("%s",string);
}
int main(void) {
    // your code goes here
    char a[] = "hello     wor   l    d";
    entab(a);
    return 0;
}