Как написать программу фильтрации на языке C?

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

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

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

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

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

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

но это просто пример.

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

4 ответов


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

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

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

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().


программа "фильтр" - это просто программа, которая читает из стандартного входного потока (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. Этот файл обычно привязан к консоли, что означает, что вы должны ввести некоторые данные вручную. Однако командные оболочки реализуют функцию pipes, которая позволяет передавать выходные данные одной команды на вход другой. Это позволяет создавать несколько программ в трубопровод для формирования мощных команд.

вот как мы могли бы использовать нашу программу фильтра (предполагая, что вы назвали полученный двоичный 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.

$

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