2012-04-03 13 views
9

Dado que UNIX tiene todos esos maravillosos programas similares a filtros (como grep, sed, tr, etc.), ¿cuál es la forma más fácil de escribir uno de esos en C estándar?¿Cómo escribo un programa de filtro en C?

Por filtro, me refiero a un programa que lee la entrada estándar, realiza una cierta manipulación de los datos, y luego lo escribe en la salida estándar. Esto es útil en la construcción de tuberías de comandos, con cada realización de alguna manipulación adicional de los datos, tales como:

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

(cada uno de los | símbolos de tubería conecta la salida estándar de la orden anterior a la entrada estándar de la a continuación, de ahí la metáfora de la tubería).

Digamos que necesitaba una que convirtiera todos los caracteres en mayúsculas a minúsculas. Y, sí, me di cuenta de esto en particular problema puede ser resuelto con el UNIX:

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

pero eso es sólo un ejemplo .

Lo que realmente busco es el código fuente C más simple para hacer un filtro de este tipo.

+2

Me estoy perdiendo algo? El 1 de abril fue hace un par de días ... –

+1

Para todas las herramientas que mencionaste, puedes encontrar fácilmente el código fuente. ¿Por qué no echar un vistazo a eso para descubrir cómo se implementan? –

+2

@Michael, no, surgió cuando estaba respondiendo otra pregunta, y me di cuenta de que no había dudas sobre esto. Según los lineamientos (SO destinado a todos los niveles de usuarios y respondiendo sus propias preguntas), pensé que lo pondría. Obviamente, sé cómo hacerlo, pero no reprenderé a la puta, sino que dejaré que otra persona responda (a menos que no lo hagan en un solo día, en cuyo caso, reprenderé al máximo :-) – paxdiablo

Respuesta

6

Usted podría utilizar getline como se describe por @hroptatyr, pero se puede hacer algo mucho más simple:

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

Creo que alguien realmente debería explicar el punto clave: un filtro es un programa que lee 'stdin' hace algo (que podría incluir no hacer nada, como 'cat') a los datos y escribe los datos transformados en' stdout'. Por supuesto, muchos filtros hacen mucho más que eso, como leer/escribir en archivos que no sean 'stdin' /' stdout' si lo indican las opciones. Pero creo que ese es el concepto central de un filtro. –

3

En pseudo-código:

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

En código real:

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); 

y filter() parece:

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

Editar: No se olvide de definir _POSIX_C_SOURCE >= 200809L o _XOPEN_SOURCE >= 700 . Y no se olvide de incluir stdio.h para getline() y ctype.h para tolower().

+0

'getline'? Whassat? :-) – paxdiablo

+0

@paxdiablo Una función probablemente definida en otro lugar. – glglgl

+0

@paxdiablo hacer 'hombre 3 getline' y estar iluminado. –

3

Un programa de "filtro" es simplemente un programa que lee del flujo de entrada estándar (stdin) y escribe en la corriente de salida estándar (stdout). Antes de escribir los datos leídos, los datos generalmente se transforman de alguna manera (si no realiza ninguna transformación o filtrado, básicamente escribió un programa cat que simplemente imprime lo que se le da). El poder del programa de filtro proviene del hecho de que no dictan de dónde proviene su entrada ni a dónde va la salida. En cambio, depende de quien llama el programa proporcionar los canales de entrada/salida.

El núcleo de un programa de filtro podría ser algo como esto (se puede utilizar esto como una plantilla para sus propios programas de filtro):

#include <stdio.h> 

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

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

Eso es todo. El trabajo real se realiza mediante una función filter que realiza la transformación que desea.Por ejemplo, aquí hay un sencillo programa que lee los caracteres del archivo de entrada, los convierte a minúsculas, y luego los imprime el archivo de salida:

#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; 
} 

Si se compila y ejecuta este programa, que va simplemente sentarse allí y espere pacientemente a que se lean los datos del archivo de entrada estándar stdin. Este archivo generalmente está vinculado a la consola, lo que significa que debe ingresar algunos datos a mano. Sin embargo, las shells de comando implementan una característica llamada pipes que le permite canalizar la salida de un comando a la entrada de otro. Esto permite componer múltiples programas en un pipeline para formar comandos potentes.

Así es como podríamos utilizar nuestro programa de filtro (suponiendo que llamó la resultante binario lower):

$ echo Hello | lower 
hello 
$ 

Dado que nuestro programa de filtro no define que los datos sean leídos está viniendo, podemos combinar con todo tipo de programas produciendo salida en stdout. Por ejemplo, aquí es cómo se puede obtener un archivo completo en minúscula (se puede utilizar type en máquinas Windows en su lugar):

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

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

$ 
+0

El 'fflush (stdout);' parece ser inútil: "Si el' main' función devuelve a su llamada original, [...] todos los archivos abiertos se cierran (por lo tanto, todos los flujos de salida se vacían) antes de la terminación del programa " (ISO/IEC 9899: 1999, 7.9.13, §5). –

+0

@undur_gongor: Para estar más feliz, estoy de acuerdo; No tuve la llamada 'fflush' en mi primera versión.Sin embargo, al probar el programa en un cuadro de Windows XP, noté que no vi ningún resultado. Explicó explícitamente "stdout" ayudando - no me molesté en consultar más (tengo experiencias menos que estelares con la API C en 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

¿Puedes explicar esto más? –

Cuestiones relacionadas