4

我有一个函数可以将文档转换为不同的格式,然后根据文档类型调用另一个函数。除了需要一些清理的 HTML 文档之外,它对于所有内容都非常简单,并且清理会根据它的来源而有所不同。所以我有一个想法,我可以将对子例程的引用传递给转换函数,这样调用者就有机会修改 HTML,有点像这样(我不在工作,所以这不是复制和粘贴) :

package Converter;
...
sub convert
{
    my ($self, $filename, $coderef) = @_;

    if ($filename =~ /html?$/i) {
        $self->_convert_html($filename, $coderef);
    }
}

sub _convert_html
{
    my ($self, $filename, $coderef) = @_;

    my $html = $self->slurp($filename);
    $coderef->(\$html); #this modifies the html
    $self->save_to_file($filename, $html);
}

然后由以下方式调用:

Converter->new->convert("./whatever.html", sub { s/<html>/<xml>/i });

我已经尝试了几种不同的方法,但我不断得到“使用未初始化的值代替 (s///)”。有什么办法可以做我想做的事吗?

谢谢

4

3 回答 3

5

如果是我,我会避免修改标量 ref 而只返回更改后的值:

sub _convert_html
{
    my ($self, $filename, $coderef) = @_;

    my $html = $self->slurp($filename);
    $html = $coderef->( $html ); #this modifies the html
    $self->save_to_file($filename, $html);
}

然而,如果你想修改一个 sub 的参数,值得知道在 Perl 中所有的 sub 参数都是通过引用传递的( 的元素@_被别名为 sub 调用的参数)。因此,您的转换子可能如下所示:

sub { $_[0] =~ s/<html>/<xml>/ }

但是如果你真的想操作$_,就像你在你想要的代码示例中那样,你需要_convert_html()看起来像:

sub _convert_html
{
    my ($self, $filename, $coderef) = @_;

    my $html = $self->slurp($filename);

    $coderef->() for $html;

    $self->save_to_file($filename, $html);
}

for是正确本地化$_. 你也可以这样做:

sub _convert_html
{
    my ($self, $filename, $coderef) = @_;

    local $_ = $self->slurp($filename);

    $coderef->();

    $self->save_to_file($filename, $_);
}
于 2010-05-17T23:15:11.717 回答
3

请记住, ans///本身对 进行操作$_,但是您的标量引用作为参数传递到您的回调子中,因此在@_数组中。

所以你可以把你的回调子改成这样:

sub { my ( $ref ) = @_; $$ref =~ s/<html>/<xml>/i }

或者,您可以利用 Perl 子例程参数的别名特性,并直接修改它:

sub _convert_html { 
    ...
    $coderef->( $html );
}

进而

sub { $_[0] =~ s/<html>/<xml>/i }

(这实际上会修改原始字符串,只要参数是标量变量而不是文字字符串。)

于 2010-05-17T23:11:26.877 回答
2

试试这个:

Converter->new->convert("./whatever.html", sub { ${$_[0]} =~ s/<html>/<xml>/i; });

您收到未初始化的值警告,因为没有对替换进行任何操作($_在其范围内未定义)。您需要告诉它在哪里可以找到它的值(在 中@_,作为参考)。

如果你想花哨,你可以让 coderef 默认对其所有参数进行操作:

sub { map { $$_ =~ s/<html>/<xml>/i } @_ }
于 2010-05-17T23:10:27.283 回答