如何用C编写一个过滤程序



由于UNIX拥有所有出色的类似过滤器的程序(如grepsedtr等),用标准C编写这些程序最简单的方法是什么?

所谓过滤器,我指的是一个程序,它读取标准输入,执行一些数据操作,然后将其写入标准输出。这在构建命令管道时很有用,每个命令管道都执行一些额外的数据操作,例如:

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

(每个|管道符号将上一个命令的标准输出连接到下一个的标准输入,因此是管道隐喻)。

假设我需要一个能将所有大写字符转换为小写字符的。是的,我意识到这个特定的问题可以用UNIX:来解决

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

但这只是一个的例子

实际上,我想要的是做这样一个过滤器的最简单的标准C源代码。

您可以使用@hropatyr所描述的getline,但您可以做一些简单得多的事情:

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

"filter"程序只是一个从标准输入流(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中读取数据。该文件通常绑定到控制台,这意味着您必须手动输入一些数据。但是,命令shell实现了一个称为管道的功能,该功能允许您将一个命令的输出管道连接到另一个的输入。这允许将多个程序组成一个管道,以形成强大的命令。

以下是我们如何使用我们的过滤器程序(假设您将生成的二进制文件称为lower):

$ echo Hello | lower
hello
$

由于我们的过滤程序没有定义要读取的数据来自哪里,我们可以将其与在stdout上产生输出的各种程序相结合。例如,以下是如何获得小写的整个文件(您可以在Windows机器上使用type):

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

在伪代码中:

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

编辑:不要忘记定义_POSIX_C_SOURCE >= 200809L_XOPEN_SOURCE >= 700。不要忘记为getline()包含stdio.h,为tolower()包含ctype.h

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 

最新更新