2012-04-03 11 views
9

Poiché UNIX ha tutti quei meravigliosi programmi di filtro (come grep, sed, tr e così via), qual è il modo più semplice per scrivere uno di quelli in C standard?Come si scrive un programma di filtro in C?

da filtro, intendo un programma che legge l'input standard, esegue alcune manipolazione dei dati, e quindi lo scrive sullo standard output. Questo è utile nella costruzione di tubazioni di comandi, ad ogni esecuzione di qualche ulteriore manipolazione dei dati, ad esempio:

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

(ciascuno dei simboli di pipe | collega l'uscita standard del comando precedente nell'ingresso standard della avanti, da qui la metafora del gasdotto).

Diciamo che avevo bisogno di uno che ha convertito tutti i caratteri maiuscoli in caratteri minuscoli. E, sì, mi rendo conto che questo particolare problema può essere risolto con l'UNIX:

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

ma questo è solo un esempio .

Quello che sto in realtà dopo è il più semplice codice sorgente C standard per fare un tale filtro.

+2

Mi sto perdendo qualcosa? 1 aprile era un paio di giorni fa ... –

+1

Per tutti gli strumenti che hai menzionato, puoi facilmente trovare il codice sorgente. Perché non dare un'occhiata a questo per scoprire come sono implementati? –

+2

@ Michael, no, è venuto fuori quando stavo rispondendo ad un'altra domanda, e ho capito che non c'era dubbio che coprisse questo. Come da linee guida (SO inteso per tutti i livelli di utenti e rispondere alle tue stesse domande), ho pensato di metterlo su. Ovviamente, io so come farlo, ma non ripeterò la puttana, lasciando che qualcun altro risponda (a meno che non lo facciano in un colpo di giorno nel qual caso, mi riproporrò al massimo :-) – paxdiablo

risposta

6

Si potrebbe utilizzare getline come descritto da @hroptatyr, ma si può fare qualcosa di molto più semplice:

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

Penso che qualcuno dovrebbe davvero spiegare il punto chiave: un filtro è un programma che legge 'stdin' fa qualcosa (che potrebbe includere non fare nulla, come 'cat') ai dati e scrivere i dati trasformati in' stdout'. Ovviamente, molti filtri fanno molto più di questo, come leggere/scrivere su file diversi da 'stdin' /' stdout' se diretto da opzioni. Ma penso che sia il concetto base di un filtro. –

3

In pseudo-codice:

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

nel codice reale:

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

e filter() assomiglia:

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

Edit: Non dimenticare di definire _POSIX_C_SOURCE >= 200809L o _XOPEN_SOURCE >= 700 . E non dimenticate di includere stdio.h per getline() e ctype.h per tolower().

+0

'getline'? Whassat? :-) – paxdiablo

+0

@paxdiablo Una funzione probabilmente definita altrove. – glglgl

+0

@paxdiablo fa 'man 3 getline' e sii illuminato. –

3

programma un "filtro" è semplicemente un programma che legge dal flusso di input standard (stdin) e scrive sul flusso di output standard (stdout). Prima di scrivere i dati letti, i dati vengono in genere trasformati in qualche modo (se non si preforma alcuna trasformazione o filtraggio, in pratica si scrive un programma cat che stampa solo ciò che gli viene dato). La potenza del programma di filtraggio deriva dal fatto che non dettano da dove proviene il loro input o dove sta andando l'output. Invece, è compito del chiamante del programma fornire i canali di input/output.

Il nucleo di un programma di filtro potrebbe essere simile a questo (è possibile utilizzare questo come modello per i propri programmi di filtro):

#include <stdio.h> 

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

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

Questo è tutto. Il lavoro effettivo viene svolto da una funzione filter che esegue la trasformazione desiderata.Per esempio, ecco un semplice programma che legge i caratteri dal file di input, li trasforma in minuscolo, e poi li stampa per il file di output:

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

Se si compila e si esegue questo programma, sarà semplicemente sedersi lì e attendere pazientemente i dati da leggere dal file di input standard stdin. Questo file è solitamente associato alla console, il che significa che devi inserire alcuni dati a mano. Tuttavia, le shell di comando implementano una funzione chiamata pipe che consente di inviare l'output di un comando all'input di un altro. Ciò consente di comporre più programmi in un pipeline per formare potenti comandi.

Ecco come potremmo usare il nostro programma di filtro (supponendo di aver chiamato il conseguente binario lower):

$ echo Hello | lower 
hello 
$ 

Poiché il nostro programma di filtro non definisce in cui i dati da leggere è venuta da, possiamo combinare con tutti i tipi di programmi che producono output su stdout. Per esempio, ecco come si può ottenere un intero file in minuscolo (è possibile utilizzare type su macchine Windows, invece):

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

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

$ 
+0

'fflush (stdout);' sembra essere inutile: "Se la funzione' main' ritorna al suo chiamante originale, [...] tutti i file aperti sono chiusi (quindi tutti i flussi di output vengono scaricati) prima della chiusura del programma ". (ISO/IEC 9899: 1999, 7.9.13, §5). –

+0

@undur_gongor: Per essere hoenst, sono d'accordo; Non avevo la chiamata 'fflush' nella mia prima versione.Tuttavia, quando ho provato il programma su una scatola di Windows XP, ho notato che non vedevo alcun output. Lo stdout di 'svuotamento esplicito 'ha aiutato - Non mi sono preoccupato di controllare ulteriormente (ho esperienze meno stellari con l'API C su 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

Puoi spiegarlo di più? –

Problemi correlati