在Perl中,我应该使用什么替代printf?

7

我需要在Perl中使用字符串替换来简化翻译,即替换多个

print "Outputting " . $n . " numbers";

通过类似于某物的方式

printf ("Outputting %d numbers", $n);

然而,我想用更容易为人类解析的东西来替换printf,比如这样:
printX ("Outputting {num} numbers", { num => $n });

或者一些更具 Perl 风格的东西。

你能推荐一些(来自 CPAN 或其他)你喜欢和使用的东西吗?

8个回答

14

那么只需简单地这样:

 print "Outputting $n numbers";

这非常像 Perl 风格。如果你不需要任何复杂的格式,字符串插值肯定是最好的选择。


谢谢您的建议,我想在大多数情况下这是一个合适的想法,但是我并不总是输出可插值变量(例如Dumper(%hash))。我需要看看它的效果如何,但我可能需要更灵活的东西... - Nikolai Prokoschenko
3
在插值中输出任意表达式的惯用语是:print "Hash is: @{[Dumper(%hash)]}"; 它不太美观,但它可以运作。 - Greg Hewgill
@Greg Hewgill 我不知道你可以做到这一点 - 太棒了! - cowgod

12

CPAN上的大多数模板引擎都能满足您的需求。这里是使用Template Toolkit的示例...

use Template;
my $tt = Template->new;

$tt->process( \"Outputting [% num %] numbers\n", { num => 100 } );


你可以使用类似以下的方式模仿所需的示例...

sub printX {
    use Template;
    my $tt = Template->new( START_TAG => '{', END_TAG => '}' );
    $tt->process( \( $_[0] . "\n" ), $_[1] );
}

如果你有一个具有唯一性约束条件的数据库表,并且你想要插入许多记录,其中一些可能已经存在于该表中,那么可以使用INSERT INTO语句的ON CONFLICT子句来执行特定操作。

printX 'Outputting {num} numbers' => { num => 100 };

5
< p > print内置函数在大多数情况下非常方便。除了变量插值之外:

print "Outputting $n numbers";    # These two lines
print "Outputting ${n} numbers";  # are equivalent

请记住print可以接受多个参数,因此如果您需要打印子程序调用的结果,则无需先将它们连接成单个字符串:

print "Output data: ", Dumper($data);

然而,如果要输出除了简单整数以外的数字,您可能需要使用printf来提供格式化方便。但是,使用print输出其他数据类型也很容易。

您可以使用join方便地输出数组:

print join ', ', @array;

结合mapkeys,输出哈希表:

print join ', ', map {"$_ : $hash{$_}"} keys %hash;

如果您想在数据周围输出引号,请使用qq运算符:

print join ', ', map {qq("$_" : "$hash{$_}"}) keys %hash;

5
如果您想简化翻译,可以考虑使用其中一个可用的L10n / i18n CPAN模块。具体而言,您的方法为什么会不够好的概述在Local :: Maketext文档中有介绍。
另一个与Locale :: Maketext配对得很好的模块是Locale :: Maketext :: Lexicon。这使您可以使用更标准的本地化格式,例如gettext的.po / .mo文件,其中有GUI工具帮助翻译人员处理所有需要翻译的文本。 Locale :: Maketext :: Lexicon还附带了一个帮助程序(xgettext.pl),可帮助保持本地化文件与需要翻译文本的模板或模块的最新状态。我过去使用过这种设置,并取得了非常好的效果。

我这里不是在谈论i18n(除了L::M::Lexicon完全不适用,稍后会讲到更多内容)而是为翻译准备字符串。在我的工作中,我们目前必须使用一种奇怪的方式提取字符串来进行自定义翻译系统。 - Nikolai Prokoschenko

4

看起来你想要一种不同的解析字符串的方式。我建议你不要这样做。只有开发者才能看到带有 %d 语法的内容,他会准确理解意思。printf 语法之所以强大,是因为它具有填充、小数等选项。

我认为你想使用更多的替换方法。用 s/{num}/$n/ 的方式更符合 Perl 风格。


1
“唯一看到带有%d语法的人是开发人员”这并不是事实,那些字符串将被翻译人员看到,而且可能是相当愚蠢的。我自己使用printf没问题,但我必须考虑其他人... - Nikolai Prokoschenko

1
鉴于您的评论是针对翻译人员的,我建议编写一个Perl脚本来剥离所有的printf()并以更简便易懂、更适合翻译人员的方式制表。
可以像这样:
while(<>)
{
    #regex for striping printf

    #print in tabulated form
}

如果您同时打印出行号,您可以轻松编写另一个程序来替换已翻译的文本。
这种解决方案不会比重构远离printf()花费更长时间,而且它是可重复使用的。

我肯定会坚持使用printf(),因为它在许多语言中都是标准的。

它几乎已经成为字符串输出的标准。就像ifor循环一样。


3
printf存在的问题是你必须将替换项的顺序正确。也就是说,如果一种语言颠倒了替换项的顺序,那么翻译者在某些printf中就会遇到困难(比如C语言)。为了使翻译更容易,你需要使用"%1$d",这样他们就可以轻松移动它。模板工具包(Template Toolkit)使这变得微不足道。 - Tanktalus

1

一般来说,Draegtun的回答很好,但如果你需要更小的东西(即更少的内存),并且不需要那么强大,你可以轻松地使用这个函数:

sub printX {
    my ( $format, $vars ) = @_;

    my @sorted_keys = sort { length($b) <=> length($a) } keys %{ $vars };
    my $re = join '|', map { "\Q$_\E" } @sorted_keys;

    $format =~ s/ \{ \s* ($re) \s* \} /$vars->{$1}/xg;

    print $format;
}

-2

如果不清楚的话,我想使用某个东西来代替Perl的printf,而不是C的printf。 - Nikolai Prokoschenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接