2012-04-03 2 views
9

Поскольку в UNIX есть все эти замечательные фильтроподобные программы (такие как grep, sed, tr и т. Д.), Что самый простой способ написать один из них в стандартном C?Как написать программу фильтрации в C?

Посредством фильтра я имею в виду программу, которая считывает стандартный ввод, выполняет некоторые манипуляции с данными и затем записывает их на стандартный вывод. Это полезно при построении трубопроводов команд, причем каждый выполняет некоторые дополнительные манипуляции с данными, такими как:

grep xyzzy input.file | tr '[A-Z]' '[a-z]' | sed 's/plugh/PLUGH/g' 

(каждый из символов | труб соединяет стандартный вывод предыдущей команды на стандартный ввод затем, следовательно, метафора трубопровода).

Предположим, мне нужен был тот, который преобразовал все символы верхнего регистра в нижний регистр. И, да, я понимаю, что это частности проблема может быть решена с помощью UNIX:

tr '[A-Z]' '[a-z]' 

, но это всего лишь пример .

То, что я на самом деле после, является простейшим стандартным исходным кодом C для создания такого фильтра.

+2

я упускаю что-то? 1 апреля было пару дней назад ... –

+1

Для всех инструментов, о которых вы упомянули, вы можете легко найти исходный код. Почему бы вам не взглянуть на это, чтобы узнать, как они реализованы? –

+2

@ Майкл, нет, это пришло, когда я отвечал на другой вопрос, и я понял, что нет никаких сомнений в этом. В соответствии с рекомендациями (SO предназначен для всех уровней пользователей и ответа на ваши собственные вопросы), я думал, что я его выдумал. Очевидно, _I_ знаю, как это сделать, но я не буду ревничать, вместо этого разрешу кому-то ответить (если только они не будут в кучу дня, в этом случае я буду ревновать до максимума :-) – paxdiablo

ответ

6

Вы можете использовать getline, как описано @hroptatyr, но вы можете сделать что-то намного проще:

#include <stdio.h> 
#include <ctype.h> 
int main(void) { 
    int c; 
    while ((c = getchar()) != EOF) 
     putchar(tolower(c)); 
    return 0; 
} 
+3

Я думаю, что кто-то должен действительно объяснить ключевой момент: фильтр - это программа, которая читает 'stdin' что-то делает (что может включать в себя не делать ничего, например 'cat') для данных, и записывать преобразованные данные в' stdout'. Конечно, многие фильтры делают гораздо больше, чем такие, как чтение/запись в файлы, отличные от 'stdin' /' stdout', если они указаны опциями. Но я думаю, что это основная концепция фильтра. –

3

В псевдокоде:

do 
    line = read(stdin); 
    filter(line); 
    print(line); 
until no_more_lines 

В реальном коде:

char *line = NULL; 
size_t len = 0U; 
ssize_t n; 

while ((n = getline(&line, &len, stdin)) >= 0) { 
     /* LINE is of length N, filter it */ 
     filter(line, n); 
     /* print it */ 
     fputs(line, stdout); 
} 
free(line); 

и filter() выглядит следующим образом:

static void filter(char *line, size_t length) 
{ 
     while ((*line++ = tolower(*line))); 
} 

Edit: Не забудьте определить _POSIX_C_SOURCE >= 200809L или _XOPEN_SOURCE >= 700 , И не забудьте указать stdio.h за getline() и ctype.h за tolower().

+0

'getline'? Whassat? :-) – paxdiablo

+0

@paxdiablo Функция, определенная в другом месте. – glglgl

+0

@paxdiablo do 'man 3 getline' и быть просветленным. –

3

программа А «фильтр» просто программа, которая считывает данные из стандартного потока ввода (stdin) и записывается в стандартный выходной поток (stdout). Перед записью прочитанных данных данные обычно каким-то образом преобразуются (если вы не преформируете какое-либо преобразование или фильтрацию, вы в основном написали программу cat, которая просто распечатывает все, что ей дано). Сила программы фильтрации исходит из того факта, что они не определяют, откуда их вход или откуда идет выход. Вместо этого для вызывающего абонента программы требуется канал ввода/вывода.

Ядро программы фильтра может выглядеть примерно так (вы можете использовать это в качестве шаблона для ваших собственных программ-фильтров):

#include <stdio.h> 

int filter(FILE *input, FILE *output); 

int main(void) 
{ 
    const int retval = filter(stdin, stdout); 
    fflush(stdout); 
    return retval; 
} 

Вот и все. Фактическая работа выполняется с помощью функции filter, которая выполняет желаемое преобразование.Например, вот простая программа, которая считывает символы из входного файла, превращает их в нижний регистр, а затем выводит их в выходной файл:

#include <stdio.h> 
#include <ctype.h> /* for tolower */ 

int filter(FILE *input, FILE *output) 
{ 
    while (!feof(input)) { 
     if (ferror(input)) { 
      return 1; 
     } 
     fputc(tolower(fgetc(input)), output); 
    } 
    return 0; 
} 

int main(void) 
{ 
    const int retval = filter(stdin, stdout); 
    fflush(stdout); 
    return retval; 
} 

Если скомпилировать и запустить эту программу, она будет просто сидеть там и терпеливо ждут чтения данных из стандартного входного файла stdin. Этот файл обычно связан с консолью, что означает, что вам нужно вводить некоторые данные вручную. Однако командные оболочки реализуют функцию, называемую pipe, которая позволяет вам вывести вывод одной команды на вход другого. Это позволяет составлять несколько программ в pipeline для создания мощных команд.

Вот как мы могли бы использовать нашу программу фильтра (предполагая, что вы назвали Образовавшийся двоичной lower):

$ echo Hello | lower 
hello 
$ 

Поскольку наша программа фильтра не определяет, где данные для чтения приходит от, мы можем объединить он со всеми видами программ, производящих выход на stdout. Например, вот как вы можете получить весь файл как строчными (вы можете использовать type на машинах Windows, вместо):

$ cat myfile.txt 
Hello, World! 
This is a simple test. 

$ cat myfile.txt | lower 
hello, world! 
this is a simple test. 

$ 
+0

'fflush (stdout);' кажется бесполезным: «Если функция' main' возвращается к исходному вызывающему, [...] все открытые файлы закрыты (следовательно, все выходные потоки сбрасываются) до завершения программы «. (ISO/IEC 9899: 1999, 7.9.13, §5). –

+0

@undur_gongor: Чтобы быть heenst, я согласен; У меня не было вызова 'fflush' в моей первой версии.Однако при попытке программы в окне Windows XP я заметил, что я не видел никакого вывода. Явное очищение 'stdout' помогло - я не стал больше проверять (у меня есть более чем звездный опыт работы с C API в Windows). –

-4
L1: 
mov dx,081 
mov cx,1 
mov bx,0 
mov ax,03f00 
int 021 
cmp ax,0 
je L2 
cmp b[081],'a' 
jb L3 
cmp b[081],'z' 
ja L3 
sub b[081],020 
L3: 
mov dx,081 
mov cx,1 
mov bx,1 
mov ax,04000 
int 021 
jmp L1 
L2: 
mov ax,04c00 
int 021 

; Example in A86 Assembler see eji.com for A86/D86 
+1

Можете ли вы объяснить это больше? –

Смежные вопросы