用(或不用)数组替换空格为TAB

huangapple go评论91阅读模式
英文:

Replacing spaces for TAB with (or without) arrays

问题

  1. 关于第一个问题,这是因为在特定情况下,为了达到制表位停止位置,可能需要一个制表符而不是单个空格。例如,如果当前位置距离下一个制表位停止位置只有 3 个空格的距离,那么用一个制表符代替这三个空格会更有效。所以问题是在这种情况下,选择使用制表符还是空格来达到相同的间距。

  2. 关于第二个问题,通常情况下,你需要存储输入字符串以便处理它,所以将其存储在数组中是合理的。这允许你轻松地遍历字符串并对其进行修改。

如果你认为程序输出了额外的空格,可能需要检查你的空格计数和制表符计数逻辑,确保在每种情况下都正确地处理了空格和制表符。如果还有问题,你可以提供更多详细信息,我可以帮助你进一步排查。

英文:

I tried to follow some advice and started reading C programming language book.
In the book there are several exercise and end of each chapter.

I've just did the following exercise:

> Write a program entab that replaces strings of blanks by the minimum number of tabs and blanks to achieve the same spacing. When either a tab or single blank would suffice to reach a stop tab, which would be given preference?

My solution to this problem was the following:


#include <stdio.h>
#include <stdlib.h>

int get_string(char string[], int index)
{
    for(int position = 0; position < index; position++)
    {
        string[position] = getchar();
        if(string[position] == '\n')
        {
            string[position] = '

#include <stdio.h>
#include <stdlib.h>
int get_string(char string[], int index)
{
for(int position = 0; position < index; position++)
{
string[position] = getchar();
if(string[position] == '\n')
{
string[position] = '\0';
return position;
}
}
return index;
}
int get_spaces(char string[], int i)
{
int temp_i = 1;
while(string[i+1] == ' ')
{
temp_i++;
i++;
}
return temp_i;
}
int get_tabs(int spaces)
{
int tabs = 0;
tabs = spaces / 4;
return tabs;
}
void entab(char string[], int max_index)
{
int i = 0;
int spaces = 0;
int tabs = 0;
while(i <= max_index)
{
if(string[i] == '\t')
{
printf("\t");
i++;
}
else if(string[i] == ' ')
{
spaces = get_spaces(string, i);
i = i + spaces;
if(spaces == 4)
{
printf("\t");
spaces = 0;
}
else if (spaces < 4)
{
for(int i = 0; i < spaces; i++)
{
putchar(' ');
}
spaces = 0;
}
else
{
tabs = get_tabs(spaces);
// printf("%d", tabs);
spaces = spaces - (tabs*4);
// printf("%d", spaces);
for(int i = 0; i < tabs; i++)
printf("\t");
for(int i = 0; i < spaces; i++)
printf(" ");
tabs = 0;
spaces = 0;
}
}
else
{
putchar(string[i]);
i++;
}
}
}
int main()
{
char string[100] = "";
int howlong = get_string(string, 100);
entab(string, howlong);
return 0;
}
'; return position; } } return index; } int get_spaces(char string[], int i) { int temp_i = 1; while(string[i+1] == ' ') { temp_i++; i++; } return temp_i; } int get_tabs(int spaces) { int tabs = 0; tabs = spaces / 4; return tabs; } void entab(char string[], int max_index) { int i = 0; int spaces = 0; int tabs = 0; while(i <= max_index) { if(string[i] == '\t') { printf("\t"); i++; } else if(string[i] == ' ') { spaces = get_spaces(string, i); i = i + spaces; if(spaces == 4) { printf("\t"); spaces = 0; } else if (spaces < 4) { for(int i = 0; i < spaces; i++) { putchar(' '); } spaces = 0; } else { tabs = get_tabs(spaces); // printf("%d", tabs); spaces = spaces - (tabs*4); // printf("%d", spaces); for(int i = 0; i < tabs; i++) printf("\t"); for(int i = 0; i < spaces; i++) printf(" "); tabs = 0; spaces = 0; } } else { putchar(string[i]); i++; } } } int main() { char string[100] = ""; int howlong = get_string(string, 100); entab(string, howlong); return 0; }

2 questions:

  1. How is it possible that to reach a tab stop, a tab might be necessary (cit. When either a tab or single blank would suffice to reach a stop tab, which would be given preference?)? I mean to reach it you need a space, so you can't prefer one or the other, it 2 different cases. Or not?

  2. I presume is not possible to do it directly of the 1st while loop without storing it in an array? or is it?

I'm pretty new to C programming, and programming in general so don't over estimate my capacities, I presume you can see that I'm not good at it, I'm trying to learn.

I dont know how to shrink the program down. It seems like an easy task yet I dont know how to address the problem.

and I think it doesn't work properly.

EDIT:

I HAVE REWROTE EVERYTHING. IM SURE ITS WORKING BUT DONT KNOW WHY IT PRINTS MORE SPACES, WHERE ARE THIS SPACES COMING FROM

答案1

得分: 1

当选用制表符或单个空格都足以到达停止标签时,应优先选择哪一个?

重点是减小输出的大小。由于空格和制表符的大小相同,所以无关紧要。所以可以使用任何一个。

我假设直接在第一个循环中进行操作而不将其存储在数组中是不可能的,对吗?

不需要使用数组。只需要跟踪三个变量:

  • 当前行中的当前位置。
  • 我们当前是否处于空白中。
  • 当前空白跨度从哪个位置开始。

算法

(支持空格、制表符和LF作为控制字符。)

  1. 将当前位置初始化为1。
  2. 将空白标志初始化为0。
  3. 创建空白开始位置变量。
  4. 循环,
    1. 读取一个字符。

    2. 如果已达到文件结尾 (EOF),

      1. 跳出循环。
    3. 如果字符是LF(换行符),

      1. 将空白标志设置为0。
      2. 将当前位置设置为1。
    4. 否则,

      1. 如果字符是空格,
        1. 如果空白标志为假,
          1. 将空白标志设置为1。
          2. 将空白开始位置设置为当前位置。
        2. 当前位置加一。
      2. 否则,
        1. 字符是制表符,
          1. 如果空白标志为假,
            1. 将空白标志设置为1。
            2. 将空白开始位置设置为当前位置。
          2. 根据当前位置和空白开始位置计算出适当数量的制表符和空格来输出。
          3. 输出它们。
          4. 将空白标志设置为假。
          5. 输出字符。
          6. 当前位置加一。
英文:

> When either a tab or single blank would suffice to reach a stop tab, which would be given preference ?

The point is to reduce the size of the output. Since spaces and tabs are the same size, it doesn't matter. So use whichever you want.

> I presume is not possible to do it directly of the 1st while loop without storing it in an array ? or is it ?

No array is necessary. It's just a question of tracking three variables:

  • The current position in the line.
  • Whether we are currently in whitespace.
  • At which position the current span of whitespace started.

Algorithm

(Supports space, tab and LF as control characters.)

  1. Initialize the current position to 1.
  2. Initialize the in whitespace flag to 0.
  3. Create the whitespace start position variable.
  4. Loop,
    1. Read a character.

    2. If EOF has been reached,

      1. Break out of loop.
    3. If the character is a LF,

      1. Set the in whitespace flag to 0.
      2. Set the current position to 1.
    4. Else,

      1. If the character is a space,
        1. If the in whitespace flag is false,
          1. Set the in whitespace flag to 1.
          2. Set the whitespace start to the current position.
        2. Add one to the current position.
      2. Else,
        1. the character is a tab,
          1. If the in whitespace flag is false,
            1. Set the in whitespace flag to 1.
            2. Set the whitespace start to the current position.
          2. Add the appropriate amount to the current position.
        2. Else,
          1. If the in whitespace flag is true,
            1. Calculate the appropriate amount of tabs and spaces to output based on the current position and the whitespace start position.
            2. Output them.
            3. Set the in whitespace flag to false.
            4. Output the character.
            5. Add one to the current position.

答案2

得分: 1

#include <stdio.h>;

#define TabWidth 4

int main(void)
{
    int CC = 0;    // 当前物理输出列为零。
    int DC = 0;    // 当前期望的输出列为零。

    while (1)
    {
        // 请求下一个字符。如果没有,退出。
        int c = getchar();
        if (c == EOF)
            break;

        // 对于换行字符,输出它并重置为新行。
        else if (c == '\n')
        {
            putchar(c);
            CC = 0;
            DC = 0;
        }

        // 对于空格,更新期望的列。
        else if (c == ' ')
            ++DC;

        /* 对于制表符,将期望的列更新为下一个制表符停止位置。我们通过
           向后“退回”与当前制表符停止位置相比超出的位置,然后前进一个完整的制表符宽度来完成这个操作。
        */
        else if (c == '\t')
            DC = DC - DC % TabWidth + TabWidth;

        /* 对于其他任何字符,输出适当数量的制表符和空格,然后再输出字符。
        */
        else
        {
            /* 在达到或超过期望位置之前,输出制表符。
            */
            while (CC / TabWidth < DC / TabWidth)
            {
                putchar('\t');
                CC = CC - CC % TabWidth + TabWidth;
            }

            // 在达到期望位置之前输出空格。
            while (CC < DC)
            {
                putchar(' ');
                ++CC;
            }

            // 输出字符。
            putchar(c);
            ++CC;
        }
    }
}
英文:
#include &lt;stdio.h&gt;


#define	TabWidth	4


int main(void)
{
	int CC = 0;	//	Current physical output column is zero.
	int DC = 0;	//	Current desired output column is zero.

	while (1)
	{
		//	Request next character.  If none, exit.
		int c = getchar();
		if (c == EOF)
			break;

		//	For a newline character, output it and reset for new line.
		else if (c == &#39;\n&#39;)
		{
			putchar(c);
			CC = 0;
			DC = 0;
		}

		//	For a space, update desired column.
		else if (c == &#39; &#39;)
			++DC;

		/*	For a tab, update desired column to next tab stop.  We do this by
			&quot;backing up&quot; as many positions as we are beyond the current tab
			stop and then advancing a full tab width.
		*/
		else if (c == &#39;\t&#39;)
			DC = DC - DC % TabWidth + TabWidth;

		/*	For any other character, output suitable tabs and spaces and then
			the character.
		*/
		else
		{
			/*	Output tabs until we reach the tab stop at or before the
				desired position.
			*/
			while (CC/TabWidth &lt; DC/TabWidth)
			{
				putchar(&#39;\t&#39;);
				CC = CC - CC % TabWidth + TabWidth;
			}

			//	Output spaces until we reach the desired position.
			while (CC &lt; DC)
			{
				putchar(&#39; &#39;);
				++CC;
			}

			//	Output the character.
			putchar(c);
			++CC;
		}
	}
}

答案3

得分: 0

以下是您要翻译的内容:

It is possible to not use an array. `entab()` is just a filter for input you can go with no array: all that matters are the tab stop size and the position on output. If you need to `entab()` a string then you can use 2 pointers.

**As I wrote in a comment above**, tab stops are positions in line. Better see them as column numbers. If tab width is 4 and first column is 0 then your tab stops are at columns 4, 8, 12, 16, 20.... If a string is &lt;TAB&gt;X --- a.k.a. `&quot;\tX\n&quot;` in `C` notation --- the X will be displayed at column 4. If you use spaces and want a X in column 10 the string is of course `&quot;         X&quot;` and uses 11 bytes. Your mission in entab is to transform such a string into `&quot;\t\t X&quot;` that uses only 5 bytes and shows the same thing on the screen.

## `C` Example ##

Suppose we have

```C
int entab(
    const char* file_in, const char* file_out,
    const int tab);

But also have

int detab(
    const char* file_in, const char* file_out,
    const int tab);

So if we take the output of entab and feed it to detab, it would be expected to get a file identical to the original file given to entab...

main.c for such a test

int main(void)
{
    const char* in     = &quot;original20.c&quot;;
    const char* interm = &quot;tab.txt&quot;;
    const char* out    = &quot;out.c&quot;;

    const int tab_s = 4;

    int status = entab(in, interm, tab_s);
    printf(
        &quot;\tentab(\&quot;%s\&quot;,\&quot;%s\&quot;,%d) returned %d\n&quot;, in,
        interm, tab_s, status);

    status = detab(interm, out, tab_s);
    printf(
        &quot;\tdetab(\&quot;%s\&quot;,\&quot;%s\&quot;,%d) returned %d\n&quot;, interm,
        out, tab_s, status);

    return 0;
}

original20.c for the example

I will use the 1st 20 lines of the original code posted by the author:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define MAX_L                                              \
    1000  // max length of array is 999. -&gt; [1000] is 
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define MAX_L                                              \
    1000  // max length of array is 999. -&gt; [1000] is \0
#define TAB_W 4  // width of atab

void entab(void)
{
    char string[MAX_L];

    char c;
    int  i = 0;
    // get string
    while ((c = getchar()) != &#39;\n&#39;)
    {
        string[i] = c;
        if (string[i] == &#39;\n&#39;) { string[i + 1] = &#39;\0&#39;; }
        else { string[i] = c; }
        ++i;
    }
}
#define TAB_W 4 // width of atab void entab(void) { char string[MAX_L]; char c; int i = 0; // get string while ((c = getchar()) != &#39;\n&#39;) { string[i] = c; if (string[i] == &#39;\n&#39;) { string[i + 1] = &#39;\0&#39;; } else { string[i] = c; } ++i; } }

output of the test

       entab(&quot;original20.c&quot;,&quot;tab.txt&quot;,4) returned 0
       detab(&quot;tab.txt&quot;,&quot;out.c&quot;,4) returned 0
PS C:\SO-EN&gt; cmd /c fc original20.c out.c
Comparing files original20.c and OUT.C
FC: no differences encountered

tab.txt is the output of entab

Original size was 475 bytes. tab.txt has 395.

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define	MAX_L											   \
	1000  // max length	of array is	999. -&gt;	[1000] is 
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define	MAX_L											   \
	1000  // max length	of array is	999. -&gt;	[1000] is \0
#define	TAB_W 4	 //	width of atab

void entab(void)
{
	char string[MAX_L];

	char c;
	int	 i = 0;
	// get string
	while ((c =	getchar()) != &#39;\n&#39;)
	{
		string[i] =	c;
		if (string[i] == &#39;\n&#39;) { string[i +	1] = &#39;\0&#39;; }
		else { string[i] = c; }
		++i;
	}
#define TAB_W 4 // width of atab void entab(void) { char string[MAX_L]; char c; int i = 0; // get string while ((c = getchar()) != &#39;\n&#39;) { string[i] = c; if (string[i] == &#39;\n&#39;) { string[i + 1] = &#39;\0&#39;; } else { string[i] = c; } ++i; }

Complete C code

#define ENTER &#39;\n&#39;
#define TAB &#39;\t&#39;
#define SPACE 0x20
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

int detab(
    const char* file_in, const char* file_out,
    const int tab);
int entab(
    const char* file_in, const char* file_out,
    const int tab);

int flush(char* const, size_t, FILE*);

int main(void)
{
    const char* in     = &quot;original20.c&quot;;
    const char* interm = &quot;tab.txt&quot;;
    const char* out    = &quot;out.c&quot;;

    const int tab_s = 4;

    int status = entab(in, interm, tab_s);
    printf(
        &quot;\tentab(\&quot;%s\&quot;,\&quot;%s\&quot;,%d) returned %d\n&quot;, in,
        interm, tab_s, status);

    status = detab(interm, out, tab_s);
    printf(
        &quot;\tdetab(\&quot;%s\&quot;,\&quot;%s\&quot;,%d) returned %d\n&quot;, interm,
        out, tab_s, status);

    return 0;
}

int detab(
    const char* file_in, const char* file_out,
    const int tab_s)
{
    int    ch    = 0;
    size_t n_col = 0;
    FILE*  in    = fopen(file_in, &quot;r&quot;);
    if (in == NULL) return -1;
    FILE* out = fopen(file_out, &quot;w&quot;);
    if (in == NULL) return -2;

    while ((ch = fgetc(in)) &gt;= 0)
    {
        switch (ch)
        {
            case TAB:
                for (int i = 0; i &lt; tab_s; i += 1)
                {   // up to tab_s spaces
                    fprintf(out, &quot; &quot;);
                    n_col += 1;
                    if (n_col % tab_s == 0) break;
                }
                break;
            case ENTER:
                fprintf(out, &quot;%

<details>
<summary>英文:</summary>

It is possible to not use an array. `entab()` is just a filter for input you can go with no array: all that matters are the tab stop size and the position on output. If you need to `entab()` a string then you can use 2 pointers.

**As I wrote in a comment above**, tab stops are positions in line. Better see them as column numbers. If tab width is 4 and first column is 0 then your tab stops are at columns 4,8,12,16,20.... If a string is &lt;TAB&gt;X --- a.k.a. `&quot;\tX\n&quot;` in `C` notation --- the X will be displayed at column 4. If you use spaces and want a X in column 10 the string is of course `&quot;         X&quot;` and uses 11 bytes. Your mission in entab is transform such a string in `&quot;\t\t X&quot;` that uses only 5 bytes and shows same thing on screen.   

## `C` Example ##    

Suppose we have 

```C
int entab(
    const char* file_in, const char* file_out,
    const int tab);

But also have

int detab(
    const char* file_in, const char* file_out,
    const int tab);

So if we take the output of entab and feed to detab: it would be expected to get a file identical to the original file given to entab...

main.c for such a test

int main(void)
{
    const char* in     = &quot;original20.c&quot;;
    const char* interm = &quot;tab.txt&quot;;
    const char* out    = &quot;out.c&quot;;

    const int tab_s = 4;

    int status = entab(in, interm, tab_s);
    printf(
        &quot;\tentab(\&quot;%s\&quot;,\&quot;%s\&quot;,%d) returned %d\n&quot;, in,
        interm, tab_s, status);

    status = detab(interm, out, tab_s);
    printf(
        &quot;\tdetab(\&quot;%s\&quot;,\&quot;%s\&quot;,%d) returned %d\n&quot;, interm,
        out, tab_s, status);

    return 0;
}

original20.c for the example

I will use the 1st 20 lines of the original code posted by the author:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define MAX_L                                              \
    1000  // max length of array is 999. -&gt; [1000] is \0
#define TAB_W 4  // width of atab

void entab(void)
{
    char string[MAX_L];

    char c;
    int  i = 0;
    // get string
    while ((c = getchar()) != &#39;\n&#39;)
    {
        string[i] = c;
        if (string[i] == &#39;\n&#39;) { string[i + 1] = &#39;\0&#39;; }
        else { string[i] = c; }
        ++i;
    }

output of the test

       entab(&quot;original20.c&quot;,&quot;tab.txt&quot;,4) returned 0
       detab(&quot;tab.txt&quot;,&quot;out.c&quot;,4) returned 0
PS C:\SO-EN&gt; cmd /c fc original20.c out.c
Comparing files original20.c and OUT.C
FC: no differences encountered

tab.txt is the output of entab

Original size was 475 bytes. tab.txt has 395.

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define	MAX_L											   \
	1000  // max length	of array is	999. -&gt;	[1000] is \0
#define	TAB_W 4	 //	width of atab

void entab(void)
{
	char string[MAX_L];

	char c;
	int	 i = 0;
	// get string
	while ((c =	getchar()) != &#39;\n&#39;)
	{
		string[i] =	c;
		if (string[i] == &#39;\n&#39;) { string[i +	1] = &#39;\0&#39;; }
		else { string[i] = c; }
		++i;
	}

Complete C code

#define ENTER &#39;\n&#39;
#define TAB &#39;\t&#39;
#define SPACE 0x20
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

int detab(
    const char* file_in, const char* file_out,
    const int tab);
int entab(
    const char* file_in, const char* file_out,
    const int tab);

int flush(char* const, size_t, FILE*);

int main(void)
{
    const char* in     = &quot;original20.c&quot;;
    const char* interm = &quot;tab.txt&quot;;
    const char* out    = &quot;out.c&quot;;

    const int tab_s = 4;

    int status = entab(in, interm, tab_s);
    printf(
        &quot;\tentab(\&quot;%s\&quot;,\&quot;%s\&quot;,%d) returned %d\n&quot;, in,
        interm, tab_s, status);

    status = detab(interm, out, tab_s);
    printf(
        &quot;\tdetab(\&quot;%s\&quot;,\&quot;%s\&quot;,%d) returned %d\n&quot;, interm,
        out, tab_s, status);

    return 0;
}

int detab(
    const char* file_in, const char* file_out,
    const int tab_s)
{
    int    ch    = 0;
    size_t n_col = 0;
    FILE*  in    = fopen(file_in, &quot;r&quot;);
    if (in == NULL) return -1;
    FILE* out = fopen(file_out, &quot;w&quot;);
    if (in == NULL) return -2;

    while ((ch = fgetc(in)) &gt;= 0)
    {
        switch (ch)
        {
            case TAB:
                for (int i = 0; i &lt; tab_s; i += 1)
                {   // up to tab_s spaces
                    fprintf(out, &quot; &quot;);
                    n_col += 1;
                    if (n_col % tab_s == 0) break;
                }
                break;
            case ENTER:
                fprintf(out, &quot;%c&quot;, ch);
                n_col = 0;
                break;
            default:
                fprintf(out, &quot;%c&quot;, ch);
                n_col += 1;
                break;
        }
    }
    fclose(in);
    fclose(out);
    return 0;
}

int entab(
    const char* file_in, const char* file_out,
    const int tab_s)
{
    int    ch       = 0;
    size_t n_col    = 0;
    char   n_spaces = 0;

    if (tab_s &lt; 2) return -1;
    FILE* in = fopen(file_in, &quot;r&quot;);
    if (in == NULL) return -2;
    FILE* out = fopen(file_out, &quot;w&quot;);
    if (in == NULL) return -3;
    char* buf = malloc(tab_s);
    if (buf == NULL) return -4;
    size_t ix = 0;

    while ((ch = fgetc(in)) &gt;= 0)
    {
        switch (ch)
        {
            case ENTER:
                if (ix == 0)
                {
                    fprintf(out, &quot;\n&quot;);
                    break;
                };
                // not empty
                flush(buf, ix, out);
                ix = 0;
                fprintf(out, &quot;\n&quot;);
                break;
            default:
                *(buf + ix) = ch;
                ix += 1;
                if (ix == tab_s)
                {
                    flush(buf, ix, out);
                    ix = 0;
                }
                break;
        }
    };
    if (ix &gt; 0)
    {
        flush(buf, ix, out);
        fprintf(out, &quot;\n&quot;);
    }
    fclose(in);
    fclose(out);
    free(buf);
    return 0;
}

int flush(char* const buf, size_t ix, FILE* out)
{
    if (out == NULL) return -1;
    if (buf == NULL) return -2;
    char* rr = buf + ix - 1;
    for (char* p = rr ;p &gt;= buf; p-=1)
    {
        if (*p != SPACE) break;
        *p = TAB;
        rr = p;
    };
    for (char*p = buf; p&lt;=rr; p += 1)
        fprintf(out, &quot;%c&quot;, *p);
    return 0;
}

This example uses a small array the size of a tab stop, for no special reason. Note that performance here is not an important issue, since we are using file I/O, a slow thing by nature.

答案4

得分: -1

  1. 如何可能要达到制表符时,可能需要一个制表符(引用:当制表符或单个空格都足以达到制表符时,应优先选择哪个?)?我的意思是要达到它,你需要一个空格,所以你不能偏好其中一个,这是两种不同的情况。对吗?

假设制表符宽度为4,在第3列时,打印空格或制表符的结果相同:达到第4列。由于空格和制表符只有一个字符,打印其中一个或另一个并不重要,以减少打印的字符数。

  1. 我假设在第一个while循环中直接做到这一点是不可能的,而不必将其存储在数组中?还是可以的?

可以在一个循环中替换空格为制表符,而不使用数组。以下是代码:

#include <stdio.h>
#include <stdlib.h>

#define TAB_WIDTH 4
#define TAB_OR_SPACE '\t'

static void endtab(void) {
    char c;
    int nb_spaces;
    int column;

    column = 0;
    nb_spaces = 0;
    while ((c = getchar()) != EOF) {
        if (c == ' ') {
            column++;
            nb_spaces++;
            if (column % TAB_WIDTH == 0) {
                // 到达制表位,因此可以用制表符替代一些空格
                if (nb_spaces == 1) {
                    // 制表符或空格?都可以
                    c = TAB_OR_SPACE;
                } else {
                    c = '\t';
                }
                nb_spaces = 0;
            } else {
                // 我们可以在这里使用一个简单的“continue”,但我认为这种方式更加优雅,以跳过“putchar”以保持与“if/else if”模式的一致性
                c = 0;
            }
        } else if (c == '\t') {
            column = 0; // 我们不需要准确的列,我们只需要对齐制表位
            nb_spaces = 0;
        } else {
            while (nb_spaces > 0) {
                putchar(' ');
                nb_spaces--;
            }
            if (c == '\r' || c == '\n') {
                column = 0;
            } else {
                column++;
            }
        }
        if (c != 0) {
            putchar(c);
        }
    }
    // 不要忘记剩下的空格
    while (nb_spaces > 0) {
        putchar(' ');
        nb_spaces--;
    }
    putchar('\n');
}

int main(int argc, char **argv) {
    endtab();
    return EXIT_SUCCESS;
}

更正:可能会在行尾和多行字符串末尾丢失一些空格。

英文:

> 1. How is it possible that to reach a tab stop, a tab might be necessary (cit. When either a tab or single blank would suffice to reach a stop tab, which would be given preference ?) ? i mean to reach it you need a space, so you cant prefere one or the other, it 2 different cases. Or not ?

Supposing tab width is 4, when in column 3, printing a space or a tab has the same result: reaching column 4. Since space and tab are one char only, printing one or the other is not really important in order to reduce the number of chars printed.

> 2. I presume is not possible to do it directly of the 1st while loop without storing it in an array ? or is it ?

It is possible to replace spaces with tabs in one loop, without using an array. Here is the code:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define TAB_WIDTH 4
#define TAB_OR_SPACE &#39;\t&#39;
static void endtab(void) {
char c;
int nb_spaces;
int column;
column = 0;
nb_spaces = 0;
while ((c = getchar()) != EOF) {
if (c == &#39; &#39;) {
column++;
nb_spaces++;
if (column % TAB_WIDTH == 0) {
// A tab position is reached, so a tab can replace some spaces
if (nb_spaces == 1) {
// Tab or space ? both works
c = TAB_OR_SPACE;
} else {
c = &#39;\t&#39;;
}
nb_spaces = 0;
} else {
// We could use a simple &quot;continue&quot; here,
// but I find more elegant this way to skip the &quot;putchar&quot; to be consistant with the use of &quot;if/else if&quot; pattern
c = 0;
}
} else if (c == &#39;\t&#39;) {
column = 0; // We don&#39;t need the exact column, we just need to be aligned on a tab stop
nb_spaces = 0;
} else {
while (nb_spaces &gt; 0) {
putchar(&#39; &#39;);
nb_spaces--;
}
if (c == &#39;\r&#39; || c == &#39;\n&#39;) {
column = 0;
} else {
column++;
}
}
if (c != 0) {
putchar(c);
}
}
// Don&#39;t forget remaining spaces
while (nb_spaces &gt; 0) {
putchar(&#39; &#39;);
nb_spaces--;
}
putchar(&#39;\n&#39;);
}
int main(int argc, char **argv) {
endtab();
return EXIT_SUCCESS;
}

Corrected: some spaces may miss at end of line and multilines string.

huangapple
  • 本文由 发表于 2023年7月31日 21:47:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76804269.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定