是否可以应用sprintf格式化HERE DOCUMENT字符串?

时间:2015-06-24 00:26:30

标签: perl

我想在此文档中嵌入令牌,然后在最后一个字符串上使用(s)printf将这些令牌替换为实际值。原因是:这使得构建HERE文档变得更加容易,其中某些部分的内容各不相同。

为了解释,这是我将如何在Python中执行此操作。从下面的小例子中可以更清楚地知道我要做什么。在Python中r"""类似于Perl <<EOT,即它构建多行原始字符串。字符串必须以"""结尾,类似于以EOT结尾的Perl。

s=r"""
\documentclass[12pt,titlepage]{article}
\begin{document}
\title{%(title)s}
\date{%(date)s}
  some text
\end{document}"""

print s % {"title": "My report","date": "1/1/2016"}

以上打印

\documentclass[12pt,titlepage]{article}
\begin{document}
\title{My report}
\date{1/1/2016}
  some text
\end{document}

请注意,%(title)%(date)最后被给定的值替换。这与执行sprintf('%s',some_string)非常相似,但在此处它应用于原始字符串本身。这非常方便,可以很容易地构建原始字符串。

这是Perl中的MWE,但是我被困在最后一部分,而且我也不知道如何做到这一切:

#!/usr/bin/perl -w
use strict;
use warnings;
my $title = "My report";
my $date  = "1/1/2016";

my $s =<<'EOT';
\documentclass[12pt,titlepage]{article}
\begin{document}
\title{%(title)s}
\date{%(date)s}
  some text
\end{document}
EOT

print($s);   #how to format this in order to replace %title and %date
             #emmbeded in $s with the values above? is it possible?

确保EOT最左边,后面没有空格。

我不知道这在Perl中是否可行。但我认为如果在Python中可行,那么在Perl中它也应该是可能的吗?

请注意,我无法在此处使用插值,即<<"EOT"因多种原因无效,必须使用非插值此处文档。所以这样的事情对我不起作用:

my $s =<<"EOT";
\documentclass[12pt,titlepage]{article}
\begin{document}
\title{$title}
\date{$date}
  some text
\end{document}
EOT

4 个答案:

答案 0 :(得分:4)

你可能会过于复杂化。是Perl有sprintf,是的你可以使用heredoc指定格式字符串,但是使用变量插值会容易得多:

#!/usr/bin/perl -w
use strict;
use warnings;
my $title = "My report";
my $date  = "1/1/2016";

my $s =<<"EOT";
\documentclass[12pt,titlepage]{article}
\begin{document}
\title{$title}
\date{$date}
  some text
\end{document}
EOT

print $s;

注意,我将EOT周围的单引号更改为双引号。 通常,您可以在双引号字符串中包含变量名称,例如:"$title"但如果您需要使用字母,数字或下划线,则只需在变量名称周围包裹花括号:{{ 1}}。

要回答问题,您可以这样做:

"${title}_word"

Perl的#!/usr/bin/perl -w use strict; use warnings; my $title = "My report"; my $date = "1/1/2016"; my $s =<<'EOT'; \documentclass[12pt,titlepage]{article} \begin{document} \title{%s} \date{%s} some text \end{document} EOT printf($s, $title, $date); 不支持命名占位符。

编辑:正如@Nasser在后来的评论中指出的那样,我的第一个例子不会像写的那样工作,因为从单引号改为双引号意味着反斜杠需要加倍并且任何文字sprintf字符串中的字符也需要转义。

答案 1 :(得分:3)

Perl的sprintf不支持命名参数,但Template::Toolkit模块的设计正是为了这类。它已经在许多项目中应用于LaTeX,Template::Plugin::Latex模块的编写是为了进一步促进这一过程

以下是使用基本模块格式化问题中的示例数据的示例。请注意,通常的用例将模板存储在单独的文本文件中,因为process方法将文件名作为其第一个参数。但它也需要一个打开的文件句柄(如果你愿意,你可以使用DATA文件句柄)或一个简单的字符串,如果它是通过引用传递的,就像这里一样

该模块具有高度可配置性,嵌入式指令构成了一种与PHP相当的综合语言,可以编写几乎适合任何情况的模板

use strict;
use warnings;

use Template;

my %vars = (
  title => 'My report',
  date  => '1/1/2016',
);

my $template =<<'EOT';
\documentclass[12pt,titlepage]{article}
\begin{document}
\title{[% title %]}
\date{[% date %]}
  some text
\end{document}
EOT

my $tt = Template->new;
$tt->process(\$template, \%vars);

输出

\documentclass[12pt,titlepage]{article}
\begin{document}
\title{My report}
\date{1/1/2016}
  some text
\end{document}

答案 2 :(得分:2)

是的,有可能。例如:

printf <<'TEMPLATE',

   %-20s    $%6.2f
   %-20s    $%6.2f
   %-20s    $%6.2f
   --------------------    -------
   TOTAL                   $%6.2f

TEMPLATE
    "Cheeseburger", 3.29,
    "Medium fries", 1.99,
    "Large soda", 1.69,
    3.29 + 1.99 + 1.69;

在此示例中,请注意第一个TEMPLATE之后的逗号。您可以在那里省略它并将其放在第二个模板之后,在新行的开头。或者您可以在第一个printf之后将其他参数放到TEMPLATE。或者你可以混淆 - 不推荐,但你可以

printf <<'TEMPLATE', "Cheeseburger", 3.29, "Medium fries"

   %-20s    $%6.2f
   %-20s    $%6.2f
   %-20s    $%6.2f
   --------------------    -------
   TOTAL                   $%6.2f

TEMPLATE
    , 1.99,
    "Large soda", 1.69,
    3.29 + 1.99 + 1.69;

但正如格兰特麦克莱恩所建议的那样,将模板放入变量中更为明智 - 如果它有意义,则使用heredoc创建,但要使printf/sprintf调用本身看起来很简单。

答案 3 :(得分:1)

要回答这个问题,有几个选择;我只讨论了两种较简单的实现方法(即printf / sprintf和正则表达式。)

  1. printf / sprintf

    如果您知道占位符的顺序,则可以使用正确的模板变量%s作为字符串,并使用printf调用中的变量插入您的值。

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my $title = "My report";
    my $date  = "1/1/2016";
    
    my $s =<<'EOT';
    \documentclass[12pt,titlepage]{article}
    \begin{document}
    \title{%s}
    \date{%s}
      some text
    \end{document}
    EOT
    
    printf( $s, $title, $date);
    
  2. 正则表达式

    使用正则表达式,您可以查找文字字符串并将其替换为某个所需的值(变量)。

    简单替换

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my $title = "My report";
    my $date  = "1/1/2016";
    
    my $s     = <<'EOT';
    \documentclass[12pt,titlepage]{article}
    \begin{document}
    \title{$title}
    \date{$date}
      some text
    \end{document}
    EOT
    
    $s =~ s/\$(title|date)/"\$$1"/eeg;            # ee is important and so is wrapping the replacement pattern in a string
    
    print $s;
    

    哈希表替换

    您可以使用替换哈希使流程更加自动化/灵活。这有助于自动生成正则表达式模式并使用哈希表来检索替换的相应值。好处是您可以向哈希添加更多或更少的变量,而无需再次触摸正则表达式(模式不会变得更大)。

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my $replace = {
      title => q{My report},
      date  => q{1/1/2016}
    };
    
    my $s = <<'EOT';
    \documentclass[12pt,titlepage]{article}
    \begin{document}
    \title{$title}
    \date{$date}
      some text
    \end{document}
    EOT
    
    $s =~ s/\$(@{[ join '|', keys %$replace ]})/$replace->{$1}/g;
    
    print $s;
    

    Regex警告

    但有许多警告。例如,自动换行可能是一个问题,具体取决于变量的中断位置 - 正则表达式未设置为查找。更值得关注的是,如果你真的想要文字字符串&#39; $ title&#39;或者&#39; $ date&#39;要在生成的文档中出现(在执行TeX代码之后),正则表达式会用一些值替换它。您必须确定哪种方法最适合您。

    通常,在模板/解析中没有单行答案,并且由于各种原因(例如,性能,可维护性,逻辑/复杂性,或者仅仅因为它无法工作)通常涉及多个语句处理否则)。