(Disclaimer: I don't understand much of Perl!)
A (nice!) answer to this question of mine advised me to use (more or less) the following perl
trick for a tricky substitution:
perl -pe 's#μ(. ?)>(. ?)(?:\&(. ?))?¢¢# sprintf(":%s:`%s`", $1, ($3 eq "" or $2 eq $3) ? $2 : "$3 <$2>")#ge'
And, indeed, that works nicely:
echo "μctanpkg>a4&a4¢¢" | perl -pe 's#μ(. ?)>(. ?)(?:\&(. ?))?¢¢# sprintf(":%s:`%s`", $1, ($3 eq "" or $2 eq $3) ? $2 : "$3 <$2>")#ge'
returns:
:ctanpkg:`a4`
Now, I need to add at the end of this substitution as many spaces as needed in order the output string is of the same length as the input one.
How could I achieve such a result?
CodePudding user response:
You can use a second sprintf
to do that, with a pattern that uses left-justify. The length can be passed in as an argument. The pattern for that is as follows.
printf "<%-*s>", 6, "a"; # prints "<a >"
You can get the length of the last successful match with $&
, as documented in perlvar.
perl -pe 's#μ(. ?)>(. ?)(?:\&(. ?))?¢¢# sprintf("%-*s", length($&), sprintf(":%s:`%s`", $1, ($3 eq "" or $2 eq $3) ? $2 : "$3 <$2>"))#ge'
With your example input, this isn't visible as it's using spaces. But if we add extra <>
to the pattern, you can see that it's working.
# V V
$ echo "μctanpkg>a4&a4¢¢" | perl -pe 's#μ(. ?)>(. ?)(?:\&(. ?))?¢¢# sprintf("<%-*s>", length($&), sprintf(":%s:`%s`", $1, ($3 eq "" or $2 eq $3) ? $2 : "$3 <$2>"))#ge'
<:ctanpkg:`a4` >
This will also work for lines with multiple matches.
echo "μctanpkg>a4&a4¢¢ μctanpkg>a4&a4¢¢" | perl -pe 's#μ(. ?)>(. ?)(?:\&(. ?))?¢¢# sprintf("<%-*s>", length($&), sprintf(":%s:`%s`", $1, ($3 eq "" or $2 eq $3) ? $2 : "$3 <$2>"))#ge'
<:ctanpkg:`a4` > <:ctanpkg:`a4` >
Please note that $&
used to incur a performance penalty in older Perls. This was fixed in 5.20. Even if you are on a version below that, your use-case probably isn't impacted very much.