Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Perl version dependent code

by Wyrdweaver (Beadle)
on Jan 24, 2019 at 20:09 UTC ( [id://1228944]=perlquestion: print w/replies, xml ) Need Help??

Wyrdweaver has asked for the wisdom of the Perl Monks concerning the following question:

I'm attempting to use case folding, when available, as the "more correct" version of case-insensitive string comparisons. However, it's only available for versions of Perl from v5.16 onwards, and I'd like to maintain backward compatibility (back to v5.8.8). So, I have a small section of version dependent code. My current solution uses stringy eval to protect it from compilation error in earlier Perl versions:
use strict; use warnings; use utf8; use 5.008008; # minimum perl version ## v5.8.8 ~ required for decent + basic Unicode support my @list = qw/ Foo bAR baZ /; if ( $] ge '5.016' ) { ## no critic ( ProhibitStringyEval RequireCheckingReturnValueOfEva +l ) eval q/@list = sort { ( CORE::fc $a ) cmp ( CORE::fc $b ) } @list; +/ } else { @list = sort { ( lc $a ) cmp ( lc $b ) } @list; } print qq/[ @list ]/,"\n";

It works but seems a bit crufty to me. I'd love to hear opinions or about any alternative formulations.

Thanks.

Replies are listed 'Best First'.
Re: Perl version dependent code (updated)
by haukex (Archbishop) on Jan 24, 2019 at 20:29 UTC

    How about:

    use if $] ge '5.016', feature => 'fc'; use if $] lt '5.016', 'Unicode::CaseFold' => 'fc';

    See Unicode::CaseFold. Otherwise you could do:

    *case_insens = $] ge '5.016' ? sub { &CORE::fc($a) cmp &CORE::fc($b) } : sub { lc $a cmp lc $b }; @list = sort {case_insens()} @list;

    Update: Used &CORE::fc() instead of CORE::fc() so that it really does work on older Perls.

      Great idea and nice implementation, but I wonder whether it wouldn't be simpler at this point to use the case_fold function of Unicode::CaseFold in both cases, i.e. irrespective of the Perl version. Something like this (not able to test right now):
      use Unicode::CaseFold qw(case_fold !fc) @list = sort {case_fold($_)} @list;
      (I know this no longer answers the OP exact question, but it seems to me this would be more straight forward.)
        simpler at this point to use the case_fold function of Unicode::CaseFold in both cases

        Sure, TIMTOWTDI :-) Personally I just prefer core Perl when reasonably possible.

        Here's another variant (Unicode::Collate has been in the core since 5.8), although the sorting order is different:

        use Unicode::Collate; @list = Unicode::Collate->new()->sort(@list);

      I've been mulling this over for a bit and expected this to show equality:

      $ ./1.version.pl a is 5.026001 b is v5.26.1 version is v5 version is v5.26.1 c is ж d is Ж did not match $ cat 1.version.pl #!/usr/bin/perl -w use 5.011; use Path::Tiny; use POSIX qw(strftime); use if $] ge '5.016', feature => 'fc'; use if $] lt '5.016', 'Unicode::CaseFold' => 'fc'; my $a = $]; say "a is $a"; my $b = $^V; say "b is $b"; printf "version is v%d\n", $a; # Perl's version printf "version is v%vd\n", $b; # Perl's version my $c = "ж"; say "c is $c"; my $d = "Ж"; say "d is $d"; if (fc($c) eq fc($d)){ say "expressions matched"; } else { say "did not match"; } __END__ $

      The characters are ж and Ж .

        my $c = "ж";

        That's an HTML entity and consists of 7 separate characters. If you typed it like this then hopefully it becomes obvious why it doesn't match against "Ж" which is an entirely different string, folding notwithstanding.

        OTOH, if you didn't type it like this but instead used a unicode literal string such as

        my $c = "ж";
        then your code is missing the absolutely necessary use utf8; pragma in order to decode this character properly.

        (Edited for typo)

Re: Perl version dependent code
by tobyink (Canon) on Jan 24, 2019 at 23:05 UTC

    Isn't this easier?

    use if $] ge '5.016', feature => 'fc'; BEGIN { eval 'fc 1' or eval 'sub fc ($) { lc $_[0] }' }; ...; @list = sort { fc $a cmp fc $b } @list;
      This should be a Babble plugin!

      map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Perl version dependent code
by Anonymous Monk on Jan 25, 2019 at 17:22 UTC

    When I ran into this I came up with

    BEGIN { *fold_case = CORE->can( 'fc' ) || CORE->can( 'lc' ) || sub { lc $_[0] }; }

    The explicit sub is because if you go back far enough lc() is not exposed in the CORE:: name space.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1228944]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2024-04-19 22:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found