Perl 与 Aspell 的接口

Perl interface with Aspell

我正在尝试通过 Perl 使用 Aspell 识别拼写错误的单词。我在没有管理员权限的 Linux 服务器上工作,这意味着我可以访问 Perl 和 Aspell,但不能访问 Text::Aspell,它是 Aspell 的 Perl 接口。

我想做一个非常简单的任务,将单词列表传递给 Aspell 并让它 return 拼错的单词。如果我要检查的单词是 "dad word lkjlkjlkj",我可以通过命令行使用以下命令执行此操作:

aspell list
dad word lkjlkjlkj

Aspell 要求最后按 CTRL + D 提交单词表。然后它将 return "lkjlkjlkj",因为这不在字典中。

为了做完全相同的事情,但通过 Perl 提交(因为我需要对数千个文档执行此操作)我已经尝试过:

my $list = q(dad word lkjlkjlkj):
my @arguments = ("aspell list", $list, "^D");
my $aspell_out=`@arguments`;
print "Aspell output = $aspell_out\n";

预期的输出是 "Aspell output = lkjlkjlkj",因为这是当您通过命令行提交这些命令时 Aspell 给出的输出。然而,实际输出只是"Aspell output = "。也就是说,Perl 不捕获 Aspell 的任何输出。没有抛出任何错误。

我不是专业的程序员,但我认为这将是一项相当简单的任务。我已经尝试了此代码的各种迭代,但没有任何效果。我做了一些挖掘,我担心也许因为 Aspell 是交互式的,我需要使用类似 Expect 的东西,但我不知道如何使用它。我也不确定它是否真的能解决我的问题。我还认为 ^D 应该是命令末尾 CTRL+D 的适当替代品,但我所知道的是它不会引发错误。我也尝试过 \cd 。无论是什么,提交命令或捕获输出显然都存在问题。

您应该退后一步,调查是否可以在没有管理员权限的情况下安装 Text::Aspell。在大多数情况下是 perfectly possible.

您可以将模块安装到主目录中。如果服务器上没有可用的 C 编译器,您可以在兼容机器上安装模块,编译并复制文件。

从程序中使用 aspell 的复杂之处在于它是一个交互式命令行驱动程序工具,正如您所怀疑的那样。但是,有一种简单的方法可以满足您的需要。

为了使用 aspell 的命令 list,需要通过 STDIN 向其传递文字,如其手册页所述。虽然我发现 GNU Aspell manual 有点难以上手,但通过它的 STDIN 将输入传递给程序很容易,我们可以将调用重写为

echo dad word lkj | aspell list

我们得到 lkj 回打印,如期。现在这可以 运行 出一个程序,就这样

my $word_list = q(word lkj good asdf);

my $cmd = qq(echo $word_list | aspell list);

my @aspell_out = qx($cmd);

print for @aspell_out;

这会打印行 lkjasdf

I assemble 出于特定原因,命令在字符串(而不是数组)中,解释如下。 qx 是反引号的运算符形式,我更喜欢它,因为它的可读性要好得多。

注意 qx 可以 return 所有输出在一个字符串中,如果在 标量上下文 (例如分配给一个标量),或者在一个在 列表上下文 中列出。在这里,我分配给一个数组,这样你就可以将每个单词作为一个元素(唉,每个单词还带有一个换行符,所以可能需要 chomp @aspell_out;)。


评论命令的列表与字符串形式

我认为通常建议对命令使用列表形式是安全的。所以我们会说

my @cmd = ('ls', '-l', $dir);  # to be run as an external command

而不是

my $cmd = "ls -l $dir";        # to be run as an external command

列表形式通常更易于管理命令,并且完全避免了 shell。

然而,这个案例有点不同

  • qx 运算符的行为并没有真正不同——数组被连接成一个字符串,运行s。我们 可以 将数组传递给它这一事实是偶然的,甚至没有记录

  • 我们需要管道输入到aspellSTDIN,shell为我们简单地完成了.我们也可以将 shell 与命令的 LIST 形式一起使用,但是我们需要明确地调用它。我们也可以通过 shell 以外的方式获得 aspellSTDIN,但这更复杂

  • 对于列表中的命令,命令名称必须是第一个单词,因此问题中的 "aspell list" 是错误的,它应该失败(没有命名的命令)...除了 在这种情况下 它不会(如果其余的都是正确的),因为对于 qx 数组被折叠变成一个字符串

最后,apsell 很好地在 C 库中公开了它的 API,并且已用于您提到的模块。我建议以用户身份安装它(不需要特权)并使用它。