练习1-21 编写程序entab,将空格串替换为最少数量的制表符和空格,但要保持单词之间的间隔不变。
本程序远远超出了题目要求,我不仅考虑了空格串,还考虑了制表符串以及空格制表符混合串。
//本程序远远超出了题目要求,我不仅考虑了空格串,还考虑了制表符串以及空格制表符混合串。
#include<stdio.h>
#define MAXLEN 1000
#define TABNUM 8
int getline(char s[], int maxlen);
void entab(char s[],int maxlen);
int countminblank(char s[]);
int main()
{
int len;
char line[1000];
while ((len = getline(line, MAXLEN)) > 0) {
entab(line,MAXLEN);
}
return 0;
}
//将输入句子储存至字符数组中,并统计句子长度,len=0时说明句子只有EOF;
int getline(char s[], int maxlen) {
int i;
char c;
for (i = 0; (c = getchar()) != EOF && c != '\n' && i < maxlen - 1;i++)
s[i] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}
//将输入句子中的每个单词以最小间隔隔开,并形成新的句子
void entab(char s[],int maxlen) {
int i,j,m,n,r,k=0;//i:源字符组的索引下标,j:目标字符组的索引下标,r:源字符组中当前空格串或者制表符串或者空格与制表符串的长度,k:目标字符组的当前光标位置
int tabnum, blanknum;
char to[MAXLEN];
int intervel;
intervel = countminblank(s);//得到输入句子中单词之间的最小间隔
for (i = 0,j=0; s[i] != '\0';) {
if (s[i] == '\t' || s[i] == '\40') {
//在单词之间插入制表符以及空格以满足最小间隔要求
tabnum =(k+intervel - 1) / TABNUM- k / TABNUM;//计算需要插入的制表符
for (m = 0,n=0; m < tabnum; m++) {
to[j++] = '\t';
n+= (TABNUM - k%TABNUM);
}
blanknum =intervel - n;//计算需要插入的空格符
for (m = 0; m < blanknum; m++)
to[j++] = '\40';
k += intervel;//更新插入制表符和空格符后的目标句子的光标位置
//得到源字符串中当前空格串或者制表符串或者空格和制表符串的长度,并更新源字符串中的索引下标
r = 0;
while (s[i+r] == '\t' || s[i+r] == '\40')
r++;
i += r;
}
//打印单词到目标字符串中
else {
to[j++] = s[i];
k++;
i++;
}
}
to[j] = '\0';
printf("%s", to);
}
//统计输入句子中单词之间的最小间隔
int countminblank(char s[]){
int blanknum=0;
int minblanknum=0;
int i=0,j=0,m=0;
for (i = 0; s[i] != '\0';) {
if (s[i] == '\t' || s[i] == '\40') {
//得到每个空格串或者制表符串或者空格制表符串的等效空格长度blanknum
for (j = 0; s[i+j] == '\t' || s[i+j] == '\40';j++) {
if (s[i + j] == '\t') {
blanknum += (TABNUM - (m%TABNUM));
m += (TABNUM - (m%TABNUM));
}
else {
blanknum += 1;
m++;
}
}
i += j;
//得到所有空格串或者制表符串或者空格制表符串的最小等效空格长度minblanknum;
if (minblanknum == 0)
minblanknum = blanknum;
if (blanknum < minblanknum)
minblanknum = blanknum;
blanknum = 0;
}
else {
i++;
m++;
}
}
return minblanknum;
}