http://qs1969.pair.com?node_id=11144541


in reply to How to use sprintf %n formatting pattern

G'day ibm1620,

You can achieve that with this code:

#!/usr/bin/env perl use strict; use warnings; my $scale = '1.......10........20........30........40........50........60'; my $max_width = length($scale) - 1; my $long_string = q{The quick brown fox jumps over the lazy dog}; my @records = ( [qw{79.3 2022 1 8}, $long_string], [qw{394571 22 10 81}, $long_string], [qw{123456.78 12345 123 1234}, $long_string], ); my $sprintf_fmt = '%.2f %d %d %d %n'; my $printf_fmt = "%s%.*s|\n"; print "$scale\n"; for my $record (@records) { my $used_so_far; printf $printf_fmt, sprintf($sprintf_fmt, @{$record}[0..3], $used_so_far), $max_width - $used_so_far, $record->[4]; }

Output:

1.......10........20........30........40........50........60 79.30 2022 1 8 The quick brown fox jumps over the lazy dog| 394571.00 22 10 81 The quick brown fox jumps over the lazy| 123456.78 12345 123 1234 The quick brown fox jumps over th|

Update: I've just noticed the '%.2f %d %d %d  %n' format would've been better as '%.2f %d/%d/%d  %n' to align with the original OP code. However, it's purely cosmetic and doesn't affect the functionality or the technique being demonstrated.

— Ken

Replies are listed 'Best First'.
Re^2: How to use sprintf %n formatting pattern
by ibm1620 (Hermit) on Jun 09, 2022 at 19:17 UTC
    Got it.

    I had thought %n would make for a more elegant solution. It doesn't look like %n saves a whole lot of work since a follow-on (s)printf statement (or clause, as you demonstrate) seems to be required, at which point the length function would provide the same info. (I think.)

      I agree. My post was mainly intended to demonstrate the use of %n as you'd requested. It was not a recommendation for production-grade code.

      I would probably just generate the potentially long string with sprintf("%.2f %d/%d/%d  %s", @$record); then use printf to truncate and print. You have a number of options here; I've shown a selection below — the first pair indicates a gotcha which you should avoid; the remaining three pairs are all potential candidates (depends on the final output you want).

      $ perl -e ' my $x = "12345"; my $y = "1234567890"; printf q{%-*2$s|}."\n", $x, 9; printf q{%-*2$s|}."\n", $y, 9; printf q{%-.*2$s|}."\n", $x, 9; printf q{%-.*2$s|}."\n", $y, 9; printf q{%-*2$.*2$s|}."\n", $x, 9; printf q{%-*2$.*2$s|}."\n", $y, 9; printf q{%-*2$.*3$s|}."\n", $x, 10, 9; printf q{%-*2$.*3$s|}."\n", $y, 10, 9; ' 12345 | 1234567890| 12345| 123456789| 12345 | 123456789| 12345 | 123456789 |

      The (possibly odd-looking) 'q{...}."\n"' is needed to avoid a 'Global symbol "$s" requires explicit package name ...' error. You could escape the '$' signs (e.g. "%-*2\$.*3\$s|\n") but, in my opinion, that makes the already somewhat cryptic format even less readable.

      I hadn't previously used '%n', so that was an interesting learning exercise for me. Thanks for the question.

      — Ken

        And I'd never heard of '*2$s' before, so thank you.
      > at which point the length function would provide the same info

      yep, exactly my thought, it's just shorter syntax.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery