Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to apply sprintf to format a HERE DOCUMENT string?

Tags:

perl

I'd like to embed tokens inside a HERE DOCUMENT and then use (s)printf on the final string to replace these tokens with actual values. The reason is: This makes it much easier to build a HERE DOCUMENT with some parts of it that are varying.

To explain, here is how I would do this in Python. From the small example below it will be more clear what I am trying to do. In Python r""" is similar to Perl <<EOT, i.e. it builds multi-line raw string. The string has to end with """ similar to Perl ending with EOT.

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"}

The above prints

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

Notice that the %(title) and %(date) were replaced at the end by values given. This is very similar to doing sprintf('%s',some_string), but here it is applied to the raw string itself. This is very handy and makes building raw string very easy.

Here is an MWE in Perl, but I am stuck on the last part, and I also do not know how to do the whole thing:

#!/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?

Make sure EOT is leftmost and has no spaces after it.

I do not know if this is even possible in Perl. But I think if it is possible in Python, it should also be possible in Perl?

Please note that I can't use interpolation in HERE DOCUMENT, i.e. <<"EOT" will not work for many reasons, and must use non interpolation HERE DOCUMENT. So something like this will not work for me:

my $s =<<"EOT";
\documentclass[12pt,titlepage]{article}
\begin{document}
\title{$title}
\date{$date}
  some text
\end{document}
EOT
like image 474
Nasser Avatar asked Dec 24 '22 17:12

Nasser


1 Answers

You may be over-complicating things. Yes Perl has sprintf and yes you can specify the format string using a heredoc, but it would be much easier to just use variable interpolation:

#!/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;

Note, I changed your single quotes around the EOT to double quotes. Normally you can just include a variable name in a double-quoted string, e.g.: "$title" but if you need to follow that with a literal letter, number or underscore, then simply wrap curly braces around the variable name: "${title}_word".

To answer the question as asked, you could do:

#!/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);

Perl's sprintf doesn't support named placeholders.

Edit: As @Nasser pointed out in a later comment my first example won't work as written, because changing from single to double quoting means that the backslashes need to be doubled up and any literal $ characters in the string would also need to be escaped.

like image 158
Grant McLean Avatar answered Dec 27 '22 11:12

Grant McLean