views:

184

answers:

5

This code works - It takes an array of full txt file paths and strips them so that when $exam_nums[$x] is called, it returns the file name

for (0..$#exam_nums)
{
 $exam_nums[$_] =~ s/\.txt$//; #remove extension
 $exam_nums[$_] =~ s/$dir//g; #remove path
}

When I try to do this for a single variable, it doesn't work. I'm calling a subroutine and sending it a present, but the variable is empty at the end. (It is getting into the if statement block, because the other lines in there run fine.) Here's the code:

Call to the sub:

notify($_);

The $_ is from a foreach(@files) loop that works

The sub:

sub notify
{
 if(shift)
 { 
  $ex_num = shift;
  $ex_num =~ s/\.txt$//; #remove extension
  $ex_num =~ s/$dir//g; #remove path
        print $ex_num;
        print "\nanything";
 }
}

I tried taking out the $ in the "remove extension" portion of the regex, but that didn't help.

+13  A: 

You're shifting TWICE. The first shift in the if statement removes the value, the second shift gets nothing. shift has a side-effect of actually modifying @_. in addition to returning the first element, it removes the first element permanently from @_.

EDIT: from man perlfunc

   shift ARRAY
   shift   Shifts the first value of the array off and returns it,
           shortening the array by 1 and moving everything down.  If there
           are no elements in the array, returns the undefined value.  If
           ARRAY is omitted, shifts the @_ array within the lexical scope
           of subroutines and formats, ...
Jim Garrison
so when I test for a shift I'm actually destroying that pointer?
CheeseConQueso
You're removing an item for the array, testing whether it's true, and then throwing it away. That item isn't there anymore, and the next shift gets the *next* item, if there is one.
hobbs
the way i originally thought things were happening was: i send a function a variable [shifted from @files array], then the function tests if it was handed a variable at all [if(shift)], and if it was, deal with it.... I don't fully understand shift and/or $_ i suppose.
CheeseConQueso
I've added a quote from the perlfunc manpage that explains it pretty clearly. `shift` by itself acts on @_
Jim Garrison
great to know... thanks again
CheeseConQueso
.... see what kind of sh*t happens when you try teaching yourself without fully learning the basics?
CheeseConQueso
+6  A: 

You are attempting to extract your ex_num argument from @_ (the argument list) twice: shift (which alters @_) is not the same as $_[0] (which just looks at the first element of @_ but does not alter it). See perldoc -f shift.

Also, your function is closing over $dir, which may or may not be your intent. (See perldoc perlfaq7 for more information about closures.) I've taken that out and added it as an additional function parameter:

sub notify
{
    my ($ex_num, $dir) = @_;
    return unless $ex_num;

    $ex_num =~ s/\.txt$//; # remove extension
    $ex_num =~ s/$dir//g;  # remove path
    print $ex_num . "\n";
}
Ether
the subroutine can be called with or without the argument, thats why I tested for it right off the bat... I see where you are going with the return unless, but I actually need it to hang around even if nothing is given to it
CheeseConQueso
The code I wrote does the same (logical) thing as what your original does: if there is no ex_num parameter passed to the function, it does nothing. You should of course not short-circuit if there is other stuff to do in the function (that you omitted from your example due to lack of relevance). :)
Ether
+5  A: 

I'd use File::Basename instead of rolling my own. It allows you to parse file paths into their directory, filename and suffix.

Nifle
interesting.... thanks
CheeseConQueso
+1  A: 

As per Jim Garrison's info, I pulled a switch to fix the problem:

sub notify
{
    $ex_num = shift;
    if($ex_num)
    { 
     $ex_num =~ s/\.txt$//; #remove extension
     $ex_num =~ s/$dir//g; #remove path
    }
}
CheeseConQueso
A: 

Uses a core module, local variables and Perl 5.10.

use 5.010;
use File::Basename;

sub notify {
    my $ex_num = shift;
    my $name = basename($ex_num, '.txt');
    say $name;
}
Peter Stuifzand