putchar('\t');
ocol += 8;
ocol &= ~07;
}
while(ocol < icol){
putchar(' ');
ocol++;
}
putchar(chr);
icol++;
ocol++;
break;
}
}
}
7.16. Составьте программу, укорачивающую строки исходного файла до заданной величины
и помещающую результат в указанный файл. Учтите, что табуляция разворачивается в нес-
колько пробелов!
7.17. Разработайте программу, укорачивающую строки входного файла до 60 символов.
Однако теперь запрещается обрубать слова.
А. Богатырев, 1992-95 - 287 - Си в UNIX
7.18. Разработайте программу, заполняющую промежутки между словами строки дополни-
тельными пробелами таким образом, чтобы длина строки была равна 60 символам.
7.19. Напишите программу, переносящую слишком длинные строки. Слова разбивать
нельзя (неумешающееся слово следует перенести целиком). Ширину строки считать равной
60.
7.20. Составьте программу, центрирующую строки файла относительно середины экрана,
т.е. добавляющую в начало строки такое количество пробелов, чтобы середина строки
печаталась в 40-ой позиции (считаем, что обычный экран имеет ширину 80 символов).
7.21. Напишите программу, отсекающую n пробелов в начале каждой строки (или n первых
любых символов). Учтите, что в файле могут быть строки короче n (например пустые
строки).
#include
/* ... текст функции untab(); ... */
void process(char name[], int n, int spacesOnly){
char line[256]; int length, shift, nline = 0;
char newname[128]; FILE *fpin, *fpout;
if((fpin = fopen(name, "r")) == NULL){
fprintf(stderr, "Не могу читать %s\n", name);
return;
}
sprintf(newname, "_%s", name); /* например */
if((fpout = fopen(newname, "w")) == NULL){
fprintf(stderr, "Не могу создать %s\n",
newname); fclose(fpin); return;
}
while(fgets(line, sizeof line, fpin)){ ++nline;
if((length = strlen(line)) &&
line[length-1] == '\n')
line[--length] = '\0'; /* обрубить '\n' */
untab(line); /* развернуть табуляции */
for(shift=0; line[shift] != '\0' && shift < n ;
++shift)
if(spacesOnly && line[shift] != ' ') break;
if(*line && shift != n ) /* Предупреждение */
fprintf(stderr,
"Начало строки #%d слишком коротко\n", nline);
fprintf(fpout, "%s\n", line+shift);
/* нельзя было fputs(line+n, fpout);
* т.к. эта позиция может быть ЗА концом строки
*/
}
fclose(fpin); fclose(fpout);
}
void main(int argc, char **argv){
if( argc != 3 ) exit(1);
process(argv[2], atoi(argv[1]) /* 8 */, 1);
exit(0);
}
7.22. Напишите программу, разбивающую файл на два по вертикали: в первый файл попа-
дает левая половина исходного файла, во второй - правая. Ширину колонки задавайте из
аргументов main(). Если же аргумент не указан - 40 позиций.
7.23. Напишите программу сортировки строк в алфавитном порядке. Учтите, что функция
strcmp() сравнивает строки в порядке кодировки, принятой на данной конкретной машине.
Русские буквы, как правило, идут не в алфавитном порядке! Следует написать функцию
А. Богатырев, 1992-95 - 288 - Си в UNIX
для алфавитного сравнения отдельных символов и, пользуясь ею, переписать функцию
strcmp().
7.24. Отсортируйте массив строк по лексикографическому убыванию, игнорируя различия
между строчными и прописными буквами.
7.25. Составьте программу дихотомического поиска в отсортированном массиве строк
(методом деления пополам).
/* Поиск в таблице методом половинного деления: dihotomia */
#include
struct elem {
char *name; /* ключ поиска */
int value;
} table[] = {
/* имена строго по алфавиту */
{ "andrew", 17 },
{ "bill", 23 },
{ "george", 55 },
{ "jack", 54 },
{ "jaw", 43 },
{ "john", 33 },
{ "mike", 99 },
{ "paul", 21 },
{ "sue", 66 }, /* SIZE - 2 */
{ NULL, -1 }, /* SIZE - 1 */
/* NULL введен только для распечатки таблицы */
};
#define SIZE (sizeof(table) / sizeof(struct elem))
/* Дихотомический поиск по таблице */
struct elem *find(s, table, size)
char *s; /* что найти ? */
struct elem table[]; /* в чем ? */
int size; /* среди первых size элементов */
{
register top, bottom, middle;
register code;
top = 0; /* начало */
bottom = size - 1; /* конец: индекс строки "sue" */
while( top <= bottom ){
middle = (top + bottom) / 2; /* середина */
/* сравнить строки */
code = strcmp( s, table[middle].name ) ;
if( code > 0 ){
top = middle + 1;
}else if( code < 0 ){
bottom = middle - 1;
}else return &table[ middle ];
}
return (struct elem *) NULL; /* не нашел */
}
А. Богатырев, 1992-95 - 289 - Си в UNIX
/* распечатка таблицы */
void printtable(tbl) register struct elem *tbl; {
for( ; tbl->name != NULL ; tbl++ ){
printf( "%-15s %d\n", tbl->name, tbl->value );
}
}
int main(){
char buf[80];
struct elem *ptr;
printtable(table);
for(;;){
printf( "-> " );
if( gets( buf ) == NULL) break; /* EOF */
if( ! strcmp( buf, "q" ))
exit(0); /* quit: выход */
ptr = find( buf, table, SIZE-1 );
if( ptr )
printf( "%d\n", ptr->value );
else {
printf( "--- Не найдено ---\n" );
printtable(table);
}
}
return 0;
}
7.26. Напишем функцию, которая преобразует строку так, что при ее печати буквы в ней
будут подчеркнуты, а цифры - выделены жирно. Формат текста с выделениями, который
создается этим примером, является общепринятым в UNIX и распознается некоторыми прог-
раммами: например, программа просмотра файлов less (more) выделяет такие буквы на
экране специальными шрифтами или инверсией фона.
#define LEN 9 /* потом напишите 256 */
char input[] = "(xxx+yyy)/123.75=?";
char output[LEN];
void main( void ){
int len=LEN, i; void bi_conv(); char c;
bi_conv(input, output, &len);
if(len > LEN){
printf("Увеличь LEN до %d\n", len);
len = LEN; /* доступный максимум */
}
for(i=0; i < len && (c = output[i]); ++i)
putchar(c);
putchar('\n');
}
/* Заметьте, что include-файлы не обязательно
* должны включаться в самом начале программы! */
#include
#include
#define PUT(c) { count++; \
if(put < *len){ *p++ = (c); ++put;}}
#define GET() (*s ? *s++ : EOF)
void bi_conv(
А. Богатырев, 1992-95 - 290 - Си в UNIX
/*IN*/ char *s,
/*OUT*/ char *p,
/*INOUT*/ int *len ){
int count, put, c;
for(count=put=0; (c=GET()) != EOF; ){
/* жирный: C\bC */
/* подчеркнутый: _\bC */
if(isalpha(c)){ PUT('_'); PUT('\b'); }
else if(isdigit(c)){ PUT( c ); PUT('\b'); }
PUT(c);
}
PUT('\0'); /* закрыть строку */
*len = count;
#undef PUT
#undef GET
}
Напишите программу для подобной обработки файла. Заметим, что для этого не нужны
промежуточные строки input и output и построчное чтение файла; все, что надо сделать,
это определить
#define PUT(c) if(c)putchar(c)
#define GET() getchar()
Напишите подобную функцию, удваивающую буквы в ссттррооккее.
7.27. Напишите программу, удаляющую из файла выделения. Для этого надо просто уда-
лять последовательности вида C\b
#include
#define NOPUT (-1) /* не символ ASCII */
/* Названия шрифтов - в перечислимом типе */
typedef enum { NORMAL=1, ITALICS, BOLD, RED=BOLD } font;
int ontty; font textfont; /* текущее выделение */
#define setfont(f) textfont=(f)
#define getfont() (textfont)
#define SetTtyFont(f) if(ontty) tfont(f)
/* Установить выделение на экране терминала */
void tfont(font f){ /* только для ANSI терминала */
static font ttyfont = NORMAL;
if(ttyfont == f) return;
printf("\033[0m"); /* set NORMAL font */
switch(ttyfont = f){
case NORMAL: /* уже сделано выше */ break;
case BOLD: printf("\033[1m"); break;
case ITALICS: /* use reverse video */
printf("\033[7m"); break;
}
}
void put(int c){ /* Вывод символа текущим цветом */
if(c == NOPUT) return; /* '\b' */
SetTtyFont(getfont()); putchar(c);
setfont(NORMAL); /* Ожидать новой C\b посл-ти */
}
void
main(){ register int c, cprev = NOPUT;
/* Стандартный вывод - это терминал ? */
ontty = isatty(fileno(stdout));
setfont(NORMAL);
while((c = getchar()) != EOF){
А. Богатырев, 1992-95 - 291 - Си в UNIX
if(c == '\b'){ /* выделение */
if((c = getchar()) == EOF) break;
if(c == cprev) setfont(BOLD);
else if(cprev == '_') setfont(ITALICS);
else /* наложение A\bB */ setfont(RED);
} else put(cprev);
cprev = c;
}
put(cprev); /* последняя буква файла */
SetTtyFont(NORMAL);
}
7.28. Напишите программу печати на принтере листинга Си-программ. Ключевые слова
языка выделяйте двойной надпечаткой. Для выдачи на терминал напишите программу, под-
черкивающую ключевые слова (подчеркивание - в следующей строке). Упрощение: выде-
ляйте не ключевые слова, а большие буквы. Указание: для двойной печати используйте
управляющий символ '\r' - возврат к началу той же строки; затем строка печатается
повторно, при этом символы, которые не должны печататься жирно, следует заменить на
пробелы (или на табуляцию, если этот символ сам есть '\t').
7.29. Напишите программу, печатающую тексты Си-программ на принтере. Выделяйте клю-
чевые слова языка жирным шрифтом, строки "строка", символы 'c' и комментарии - курси-
вом. Шрифты для EPSON-FX совместимых принтеров (например EP-2424) переключаются
такими управляющими последовательностями (ESC означает символ '\033'):
ВКЛЮЧЕНИЕ ВЫКЛЮЧЕНИЕ
жирный шрифт (bold) ESC G ESC H
утолщенный шрифт (emphasized) ESC E ESC F
курсив (italics) ESC 4 ESC 5
подчеркивание (underline) ESC - 1 ESC - 0