# length counts code points. A reader counts graphemes, a file stores bytes,
# and the same-looking word can be spelled with different code points. Perl has
# all three rulers -- \X for graphemes, Encode for bytes, Unicode::Normalize to
# make two spellings one -- but length is the only one it reaches for itself.
use v5.36;
use utf8;
use Encode qw(encode);
use Unicode::Normalize qw(NFC NFD);

binmode STDOUT, ':encoding(UTF-8)';

sub yn { $_[0] ? 'yes' : 'no' }    # no signature: a failed match in an argument list passes nothing
sub graphemes ($s) { scalar(() = $s =~ /\X/g) }

my @samples = (
    ['café, composed (NFC)',   "caf\x{E9}"],
    ['café, decomposed (NFD)', "cafe\x{301}"],
    ['zażółć',                 "za\x{17C}\x{F3}\x{142}\x{107}"],
    ['flag of Poland',         "\x{1F1F5}\x{1F1F1}"],
    ['family emoji',           "\x{1F468}\x{200D}\x{1F469}\x{200D}\x{1F467}"],
);

say "--- three rulers ---";
printf "%-24s %5s %6s %9s\n", '', 'bytes', 'length', 'graphemes';
for my $sample (@samples) {
    my ($label, $s) = @$sample;
    printf "%-24s %5d %6d %9d\n", $label, length encode('UTF-8', $s), length $s, graphemes($s);
}
say "";

my ($nfc, $nfd) = ("caf\x{E9}", "cafe\x{301}");
say "--- two spellings of café ---";
say "nfc eq nfd:              ", yn($nfc eq $nfd);
say "NFC(nfd) eq nfc:         ", yn(NFC($nfd) eq $nfc);
say "nfd =~ /^cafe/:          ", yn($nfd =~ /^cafe/), "   the e is there, with its accent after it";
say "index(nfd, 'cafe'):      ", index($nfd, 'cafe');
say "length NFD('zażółć'):    ", length NFD("za\x{17C}\x{F3}\x{142}\x{107}"), "   ł has no decomposition";
say "";

say "--- cutting by code point cuts letters ---";
say "substr(nfd, 0, 4):       [", substr($nfd, 0, 4), "]";
say "reverse nfd:             [", scalar reverse($nfd), "]";
say "reverse by \\X:           [", join('', reverse $nfd =~ /\X/g), "]";
say "reverse flag:            [", scalar reverse("\x{1F1F5}\x{1F1F1}"), "]   PL reversed is LP";
say "sprintf '%-6s|':         [", sprintf('%-6s|', $nfc), "] [", sprintf('%-6s|', $nfd), "]";
