第二章 字符和字符串的转换
一、文本中制表符和空格的相互转换
(一)制表符转换为空格
问题描述:
|
要解决这个问题,首先要弄清楚文本中tab的性质,我们以vim编辑器为例进行探究。
说明:在每个tab后面都会紧跟一个2,以此来标记2前面是一个tab,另外为了发现tab的规律,特在文本中插入几行用来标记列号的数字
下面就是tab在vim文本编辑器中的效果:
每个数字2前面都有一个tab,很容易观察到,每个2都会出现在列号为1的位置,也就是说输入一个tab后,会让光标出现在某些固定的列,而且这些固定的列会是第9列、第17列、第25列……那么,如果在第8列后(此时光标位于第9列)再输入一个tab(输入后tab出现在第9列)会怎样呢?光标会停留在第9列,还是会跳转到第17列呢?我们观察这一情况:
答案是:光标跳转到第17列。也就是说,tab一定是占位符,在输入tab后不会出现光标位置不变的情况。
我们还可以观察到:
如果tab出现在第1~8列,光标会跳转到第9列
如果tab出现在第9~16列,光标会跳转到第17列
如果tab出现在第n列,光标会跳转到第((n-1)/8+1)*8+1列
……
因此,如果要用空格代替tab,并且不改变文本的布局,就要知道tab所处的列,然后将tab替换为相应数目的空格,使光标处于正确的位置即可。那么,如何得到tab所在列呢?当然,我们首先想到的应该是字符计数,但是,单纯的字符计数能够知道tab所处的列吗?我们假设输入的文本(tab用\t表示)是11\t21\t1,此时,如果使用单纯的字符计数,第一个tab位于第3列,第二个tab位于第6列,根据得到的规律,它们都将光标移至第9列,这显然是不正确的。正确计算列号的方式应该是:第一个tab位于第3列,为了将光标移至第9列,应该把这个tab换为6个空格,然后,将这些用于替换的空格也算入字符计数中,这时,第二个tab就会位于第11列,为了将光标移至第17列,应该把tab换为6个空格。
这样我们便得到了解决这个问题的方案:
逐个读取字符,如果读到tab,根据此时的字符数(列号)n,将这个tab替换为(n/8+1)*8-n个空格输出,并将此时的字符数记为:(n/8+1)*8;如果是非tab就直接输出字符,并计数。依此思路编写程序,便可以解决问题。 (另外,注意换行符对程序的影响:如果换行,则需要重新计算字符的列号)
下面是代码和测试结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/* * 将文本中的tab转换为等效的空格,并且不改变文本原先的布局 */ #include <stdio.h> #define INTERVAL 8 int main ( void ) { int count; int ch; int i; int space_num; count = 0; while ( (ch=getchar()) != EOF ) { if ( '\t' == ch ) { space_num = (count/INTERVAL+1)*INTERVAL-count; for ( i=0; i<space_num; i++ ) putchar ( ' ' ); count = (count/INTERVAL+1)*INTERVAL; } else { count++; putchar ( ch ); } if ( '\n' == ch ) count = 0; } return 0; } |
在上面的方法中,