http://qs321.pair.com?node_id=506805

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

Hello all, I have an array of string X and I am searching for var Y inside the string, but I cannot get it to find the occurance of the variable. Really, this is in an array of string. I've searched the Categorized Questions and Answers section, but that did not help. Here is a snippet, $X is space delimited. $X = Rescue21 EEC System Management Rescue21 EEC System Management Rescue21 EEC System Management C:\Rescue21\Executables\AlarmForwarderServer.exe Automatic Manual $Y = AlarmForwarderServer.exe
foreach $Y(@dependantFiles ) { foreach $X(@namedFiles) { if( $X =~ m/$Y/gi) { print "Found it\n" last; } } next; }
After the match is found, how do you pull the first part of the text out of the string? Thanks for helping a NooB.

Replies are listed 'Best First'.
Re: regex expression help
by sauoq (Abbot) on Nov 08, 2005 at 17:10 UTC

    If your $X and $Y values are really what you gave us, that should work. This is a shot in the dark, but is it possible your @dependantFiles values contain newlines? (Did you read them from a file?) I would check to see if the variables contain exactly what you think they do. Try print "Y: '$Y'\nX: '$X'\n"; for instance.

    -sauoq
    "My two cents aren't worth a dime.";
    
      Yes, the values were grabbed from a file. How will that prind statement show newlines? I have alread checked the values in the file. Would it make a difference if I made the string I'm searching in seperated via commas?
        Yes, the values were grabbed from a file. How will that prind statement show newlines?

        Well, if you enclose the values in single quotes, and there is a newline in the value, you'll see the ending quote on a line by itself.

        I have alread checked the values in the file.

        Checked them for what? If you've got like one filename per line, and you are reading them in with something like my @dependantFiles = <FH>; then each value in @dependantFiles will be terminated by a newline. You might just try calling chomp(@dependantFiles) before the code you posted. That may be all you need. (Although, you could stand to make some other improvements.)

        Would it make a difference if I made the string I'm searching in seperated via commas?

        No. Given the code you gave us, it doesn't matter what is separating the values in your $X strings. You aren't doing anything with the separating character or even with the separate values. You are simply treating it as one string.

        -sauoq
        "My two cents aren't worth a dime.";
        
Re: regex expression help
by Trix606 (Monk) on Nov 08, 2005 at 17:42 UTC
    I am not quite sure from your question whether you are having a problem with the match itself, or simply are asking about printing what precedes the match.

    As for the match I tried your code and sample data and it works, ( once you add a semi-colon after Found it\n").

    You can print the contents of $` to get what precedes your match.

    Check out perldoc perlvar for info on $` and other variables you can use with a regex and more.

Re: regex expression help
by bangers (Pilgrim) on Nov 08, 2005 at 17:10 UTC
    This should work
    my @dependantFiles = ( 'aa', 'bb', 'cdef' ); my @namedFiles = ( 'cc', 'bb', 'dde' ); for my $y ( @dependantFiles ) { if( grep /$y/i, @namedFiles) { print "Found $y \n"; last; } else { print "not $y \n"; } }
      on second thoughts, probably best to use this:
      my @dependantFiles = ( 'aa', 'bb', 'cdef' ); my @namedFiles = ( 'cc', 'bb', 'dde' ); for my $y ( @dependantFiles ) { if( grep /^$y$/i, @namedFiles) { print "Found $y \n"; last; } else { print "not $y \n"; } }
      that way the file 'abc' in @namedFiles won't be tripped up if 'abcd' is in @dependantFiles
Re: regex expression help
by Animator (Hermit) on Nov 08, 2005 at 18:10 UTC

    The easiest way to get the part of the data before the string was found is to capture all of it.

    Another approach is the one [id://Trix606] suggested... but be careful with it (as perlvar says): it impose a penalty on every regular expression... which slows down each match. Which is a bad idea.

    Yet another approach is mentioned in the perlretut pod.

    Some comments on this code. (Maybe relevant, maybe not.)

    First, posting the code you are actually using might proof to be easier... and will result in better help.
    (I say this because you have a syntax error in your code... (a missing ; after the print statement). This makes me guess that you didn't post the actual code)

    Second, What if @dependantFiles contains a regex charachters? Do you want them to be interpreted or not? If not then you should look at the quotemeta function and/or \Q and \E in one of the perlre PODS (perlreref might be a good starting place).

    Speaking about the regex: there is no need for the regex to be global. So drop the /g.

    Another good idea is to use a lexical loop variable... it will make your live easier...

    Doing next; at the end of the loop is pretty useless... (but it might make more sense in your actual code... (as in, the next is in an if-statement, and there is some other code behind it))

Re: regex expression help
by ikegami (Patriarch) on Nov 08, 2005 at 19:36 UTC

    For the input you gave, it won't make a difference, but if $Y is a constant string, not a regexp, you should escape it, as follows:

    foreach $Y (@dependantFiles) { foreach $X (@namedFiles) { if( $X =~ m/\Q$Y\E/i) { print "Found it\n" last; } } }

    I also removed the useless 'g' option and the useless 'next'.

    But if it's not a regexp, why use m// at all! index is much faster:

    foreach $Y (@dependantFiles) { foreach $X (@namedFiles) { if (index(lc($X), lc($Y)) >= 0) { print "Found it\n" last; } } }

    With a slight optimization:

    foreach $Y (@dependantFiles) { my $lcY = lc($Y); foreach $X (@namedFiles) { if (index(lc($X), $lcY) >= 0) { print "Found it\n" last; } } }

    If the $Y will always be at the end of $X, the following is even faster and more accurate:

    foreach $Y (@dependantFiles) { my $lcY = lc($Y); foreach $X (@namedFiles) { if (lc(substr($X, -length($Y))) eq $lcY) { print "Found it\n" last; } } }

    I haven't solved the problem where $X is c:\path\ab.exe and $Y is b.exe. There are a couple of solutions, but I'll let you try to solve it before I say more.