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

I'm doing an overhaul on one of my modules (I'm running v5.22.0) and am hitting "Unescaped left brace in regex is deprecated" in a mock script meant to be transformed into a unit test. The offending line is the fourth-from-last, because $_ has a { in it.

How can I escape or otherwise work around this issue, so it'll be backward and forward compatible?

#!/usr/bin/perl use warnings; use strict; use File::Copy; use Tie::File; my $f = 't/sample.data'; my $wf = 't/write_sample.data'; copy($f, $wf); tie my @wfh, 'Tie::File', $wf; for (@wfh){ if (/sub seven/){ $_ =~ s/seven/xxxxx/; } } untie @wfh; open my $wfh, '<', $wf or die "Can't open test written file $wf: $!"; open my $fh, '<', $f or die "Can't open original test file $f: $!"; my @wf = <$wfh>; my @f = <$fh>; for (@f){ if (! grep /$_/, @wf){ print "$_\n"; } }

-stevieb

Replies are listed 'Best First'.
Re: "Unescaped left brace in regex is deprecated"
by Anonymous Monk on Jul 18, 2015 at 00:36 UTC

    From the perldelta for Perl v5.22.0:

    A literal { should now be escaped in a pattern

    If you want a literal left curly bracket (also called a left brace) in a regular expression pattern, you should now escape it by either preceding it with a backslash (\{) or enclosing it within square brackets [{], or by using \Q; otherwise a deprecation warning will be raised. This was first announced as forthcoming in the v5.16 release; it will allow future extensions to the language to happen.

    But ... what is grep /$_/, @wf supposed to be doing?

      I'm going to stop playing for today... right from the morning, it hasn't been my day. The silliness of what I've been attempting to do is ridiculous. We all have these days, right?

Re: "Unescaped left brace in regex is deprecated"
by Anonymous Monk on Jul 18, 2015 at 00:40 UTC

      Meant for both Anonymonks... \Q slipped my mind. Been that kind of day :)

Re: "Unescaped left brace in regex is deprecated"
by stevieb (Canon) on Jul 18, 2015 at 02:35 UTC

    Been a long day with 'real life' issues I've been trying to use Perl to help me pretend they didn't happen... here's a base test I was thinking.

    #!perl -T use Test::More tests => 9; use File::Copy qw(copy); use Tie::File; my $f = 't/sample.data'; my $wf = 't/write_sample.data'; copy($f, $wf); tie my @wfh, 'Tie::File', $wf; for (@wfh){ if (/sub seven/){ $_ =~ s/seven/xxxxx/; } } untie @wfh; #1 eval { open my $wfh, '<', $wf or die "Can't open test written file $wf: $!"; }; ok (! $@, "copy of test sample file ok" ); open my $wfh, '<', $wf or die $!; #2 eval { open my $fh, '<', $f or die "Can't open original test file $f: $!"; }; ok (! $@, "can open orig test file after tie/untie/copy" ); my @wf = <$wfh>; my @f = <$fh>; my $count = scalar @f; my @changes; #3 for (0..$count){ if ($wf[$_] and $wf[$_] ne $f[$_]){ push @changes, $wf[$_]; } } is ( scalar(@changes), 1, "search/replace does the right thing, in the + right spot" ); #4 eval { close $fh; }; ok (! $@, "no problem closing the original test read file" ); close $fh; #5 eval { close $wfh; }; ok (! $@, "no problem closing the test write file" ); close $wfh; #6 eval { unlink $wf }; ok (! $@, "no problem deleting the test write file" ); #7 eval { open my $wfh, '<', $wf or die "Can't open $wfh: $!"; }; ok ($@, "after unlink of test write file, it can't be opened" ); #8 is (@changes, 1, "search_replace on one line replaces only one line" ) +;

      To make the test plan a bit more clear, maybe use some of the functions from Test::Exception to consolidate some operations. E.g., the last few tests above might be re-written (untested):

      lives_ok { close $fh or die "closing '$f': $!"; close $wfh or die "closing '$wf': $!"; unlink $wf or die "unlinking '$wf': $!"; } 'file cleanup ok'; dies_ok { open my $wfh, '<', $wf or die "opening '$wf': $!"; } "after unlink of '$wf': cannot re-open for read";
      (In place of  dies_ok() you could use  throws_ok() and check for a specific "file does not exist" error message.)


      Give a man a fish:  <%-(-(-(-<

        Thanks a lot AnomalousMonk, that's some great insight. I'll apply that to these types of tests for sure. I've also run into a situation where in a test I needed to run past an exit(), and am becoming familiar with Test::Trap.

        The following example hasn't yet incorporated your Test::Exception (I also noticed that I wasn't using strict or warnings which has turned out to be very significant for the stability and predictability of a test suite).

        #!perl -T use warnings; use strict; use Test::More tests => 8; use Test::Trap; BEGIN {#1 use_ok( 'Devel::Examine::Subs' ) || print "Bail out!\n"; } my $des = Devel::Examine::Subs->new({ file => 't/sample.data', engine => 'all', }); {#2 - core dump my $file = 't/core_dump.debug'; do { eval { open STDOUT, '>', $file or die $!; }; ok (! $@, "STDOUT redirected for core dump"); my @exit = trap { $des->run({core_dump => 1}); }; eval { print STDOUT $trap->stdout; }; is (! $trap->stdout, '', "output to stdout" ); ok (! $@, "core dump gave no errors" ); }; eval { open my $fh, '<', $file or die $!; }; ok (! $@, "core dump output file exists and can be read" ); open my $fh, '<', $file or die $!; my @lines = <$fh>; is (@lines, 183, "Based on test data, core dump dumps the correct +info" ); eval { close $fh; }; ok (! $@, "core dump output file closed successfully" ); eval { unlink $file; }; ok (! $@, "core dump temp file deleted successfully" ); }

        -stevieb

Re: "Unescaped left brace in regex is deprecated"
by stevieb (Canon) on Jul 18, 2015 at 01:39 UTC

    Without grep which I was using foolishly...

    my $n = scalar @f; for (0..$n){ if ($wf[$_] and $wf[$_] ne $f[$_]){ print "$wf[$_]"; } }

    I'm sure there's a much better way, but I digress.

      For when, with the dawn of a new day, your mind is more clear:

      my $n = scalar @f;

      scalar @f gives the number of elements of the array, which is probably not what you want if you're iterating over the elements of the array:

      c:\@Work\Perl>perl -wMstrict -le "my @f = (9, 8, 7); my $n = scalar @f; for (0 .. $n) { print qq{index $_: element $f[$_]}; } " index 0: element 9 index 1: element 8 index 2: element 7 Use of uninitialized value in concatenation (.) or string at -e line 1 +. index 3: element

      Better to use  $#f which yields the highest index of the array. Then,
          my $n = $#f;
      would give you something sensible, and you don't even really need the intermediate  $n variable:

      c:\@Work\Perl>perl -wMstrict -le "my @f = (9, 8, 7); for (0 .. $#f) { print qq{index $_: element $f[$_]}; } " index 0: element 9 index 1: element 8 index 2: element 7


      Give a man a fish:  <%-(-(-(-<

Re: "Unescaped left brace in regex is deprecated"
by Anonymous Monk on Jul 18, 2015 at 00:57 UTC

    I'm pretty tired (Friday and all) so I may not be wrapping my head around this properly, but won't grep /\Q$_/, @wf just be matching the elements of @wf against themselves, and not @f like you probably intended?

    for my $ff (@f) { if (! grep {$ff=~/\Q$_/} @wf){ print "$ff\n"; } }