Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

How do I get an exclusion with grep?

by Lady_Aleena (Curate)
on Apr 27, 2020 at 03:17 UTC ( #11116100=perlquestion: print w/replies, xml ) Need Help??

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

I am trying to exclude certain items with grep, however, my exclusion is not working.

Here is the snippet I am working on where I do not want the string  right appended if the word in the $text appears in one of the items in the list. Everything is getting  right appended currently.

my @big_images = $opt{big} ? @{$opt{big}} : (); for my $cross_file (@cross_files) { my $text = textify($cross_file); my $class = 'svg_group'; $class .= ' right' unless grep(/$text/i, @big_images); }

So, if I use it like the following, I do not want right appended to $class if Smart is in $text.

my $magic = crossover_magic( big => ['Smart'] );

Update: I found that $text needs to be an exact match. I would prefer not having to use exact matches. I added case insensitivity to it also.

Here is the whole subroutine if there is something in there that might be affecting things that I am not seeing.

sub crossover_magic { my %opt = @_; our $magic; my $open_directory = file_directory('Fandom/Crossovers', 'imagesd'); my $link_directory = file_directory('Fandom/Crossovers', 'images'); my @cross_files = file_list($open_directory); my @big_images = $opt{big} ? @{$opt{big}} : (); for my $cross_file (@cross_files) { my $link = "$link_directory/$cross_file"; my $text = textify($cross_file); my $class = 'svg_group'; $class .= ' right' unless grep(/$text/i, @big_images); my $title = "$text chart"; $magic->{$text} = sub { figure(6, sub { line(7, anchor( '', { 'href' => $link, 'target' => 'new' })); line(7, object( '', { 'data' => $link, 'type' => 'image/svg+xm +l'})); }, { 'class' => "$class", 'title' => $title }); }; } my $series = series('data', 'me'); my $series_list = movie_option('series'); for my $item (sort keys %$series_list) { my $magic_search; my $magic_text; if ($series->{$item}) { for my $program (@{$series->{$item}->{programs}}) { my $magic_key = $item eq $program ? "$program-single" : $pr +ogram; $magic_text = textify($program); $magic_search = searchify($item, [$program]); $magic->{$magic_key} = qq(A<I<$magic_text>|href="../../Movies/ +Movies_by_series.pl?series=$magic_search">); } } $magic_text = $item eq 'Scorpion' ? '&#60;/Scorpion&#62;' : $item eq 'EUReKA' ? 'EURSUP<e>KA' : textify($item); $magic_search = searchify($item); $magic->{$item} = qq(A<I<$magic_text>|href="../../Movies/Movies_by +_series.pl?series=$magic_search">); } return $magic; }

My OS is Debian 10 (Buster); my perl version is 5.28.1.

No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
Lady Aleena

Replies are listed 'Best First'.
Re: How do I get an exclusion with grep?
by hippo (Chancellor) on Apr 27, 2020 at 08:24 UTC
    I found that $text needs to be an exact match. I would prefer not having to use exact matches. I added case insensitivity to it also.

    This suggests to me that you might be performing the match the wrong way round, i.e. you want to look case-insensitively within $text for things which match the patterns held in @big_images. If that's the case then you need to switch the grep so that $_ becomes the pattern. e.g.:

    $class .= ' right' unless grep($text =~ /$_/i, @big_images);

    Here's the SSCCE:

    use strict; use warnings; use Test::More tests => 4; my $text = 'Only smartees have the answer!'; ok grep ($text =~ /$_/i, 'Smart'), 'Case-insensitive match'; ok grep ($text =~ /$_/i, 'foo', 'Smart', 'bar'), 'Match one of three'; ok grep ($text =~ /$_/i, 'foo', 'Smart', 'art'), 'Match two of three'; ok !grep ($text =~ /$_/i, 'foo', 'baz'), 'Match none';

    HTH.

      Thank you hippo, that worked! 8)

      My OS is Debian 10 (Buster); my perl version is 5.28.1.

      No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
      Lady Aleena
Re: How do I get an exclusion with grep?
by kcott (Bishop) on Apr 27, 2020 at 05:59 UTC

    G'day Lady Aleena,

    Without knowing the exact contents of @big_images and @cross_files, or what transformation occurs when textify() is run, it's not possible to give a direct answer.

    As a first step, I recommend you print those values inside delimiters to identify parts of the string that may not be immediately obvious. For example, these may appear the same when printed directly:

    $ perl -E 'say for "qwe", "qwe\n"' qwe qwe

    With delimiters, the difference is obvious:

    $ perl -E 'say "|$_|" for "qwe", "qwe\n"' |qwe| |qwe |

    Doing this may highlight the problem and allow you to solve it yourself. If not, post the results and we can have another look at it.

    You're reading the entirety of @big_images in every iteration of the for loop. A slightly more efficient way would be to only read as much as you need: see the List::Util function first. Not reading that array at all inside the for loop would be much better; something like:

    my %big_image = map +(fc($_) => 1), $opt{big} ? @{$opt{big}} : (); for my $cross_file (@cross_files) { my $text = textify($cross_file); my $class = 'svg_group'; $class .= ' right' unless exists $big_image{fc $text}; }

    Note: Testing $opt{big} for truth may be an issue. If --big (I'm guessing at the option) isn't supplied, will the key, big, be absent or will it have an empty arrayref ([]) as its value? If it's an empty arrayref, the value (something like ARRAY(0xhhhhhhhh)) will always be true and a better test would be 0+@{$opt{big}}.

    $ perl -E 'my %opt = ( big => [] ); say $opt{big}' ARRAY(0x600003a90) $ perl -E 'my %opt = ( big => [] ); say 0+@{$opt{big}}' 0

    However, if the key is absent, a better test would be exists($opt{big}).

    Depending on other code not shown, a combination of both of those (exists($opt{big}) && 0+@{$opt{big}}) may be even better.

    — Ken

      The only thing I left out of the big block of code with the crossover_magic is the "heading" of the module. So, here is the contents of @cross_files and the results of textify on them side-by-side. textify is at the bottom of this post. Also, if you need any other subroutines, let me know.

      @cross_filestextified
      [ 'key.svg', 'Spy_Machete.svg', 'Two_Half_Bang.svg', 'McHale_UNCLE_Smart.svg', 'Howling_Gremlins.svg', 'Dragnet.svg', 'View_Scream.svg', 'blank_spinoff.svg', 'Westphall.png', 'Westerns_in_Crisis.svg', 'Mary_Tyler_Moore.svg', 'Better_Fast.svg', 'Terminator_Abyss.svg', 'Frozen_Hatchet.svg', 'Babylon_5_Cases.svg', 'Columbo.svg', 'crossover_archive.zip', 'Burkes_Law.svg', 'temp.svg', 'Westphall.svg', 'Arriving_to_Westphall.svg', 'key-big.svg', 'Departing_from_Westphall.svg', 'MCU.svg', 'Horror.svg', 'Alices_Hazzard.svg' ];
      [ 'key', 'Spy Machete', 'Two Half Bang', 'McHale UNCLE Smart', 'Howling Gremlins', 'Dragnet', 'View Scream', 'blank spinoff', 'Westphall', 'Westerns in Crisis', 'Mary Tyler Moore', 'Better Fast', 'Terminator Abyss', 'Frozen Hatchet', 'Babylon 5 Cases', 'Columbo', 'crossover archive', 'Burkes Law', 'temp', 'Westphall', 'Arriving to Westphall', 'key-big', 'Departing from Westphall', 'MCU', 'Horror', 'Alices Hazzard' ];

      I am using this in scripts, so no -- options. Here is how crossover_magic is being used in the scripts.

      my $magic = crossover_magic(); # no big svgs here, s +o no $opt{big} # The rest have only one that should NOT have ' right' appended to $cl +ass my $magic = crossover_magic( big => ['Horror']); my $magic = crossover_magic( big => ['Westerns in Crisis']); # I'd lik +e to use the word 'Westerns' only my $magic = crossover_magic( big => ['McHale UNCLE Smart']); # I'd lik +e to use ONE word only # All svgs with Westphall in the name are big, so again no ' right' my $magic = crossover_magic( big => ['Westphall']); my $magic = crossover_magic( big => ['Arriving to Westphall']); # I prefer my $magic = crossover_magic( big => ['Westphall']); my $magic = crossover_magic( big => ['Departing from Westphall']); # I prefer my $magic = crossover_magic( big => ['Westphall']);

      Here is textify for you to peruse. It looks messy, but regexen are never pretty for me at least.

      sub textify { my ($text, $opt) = @_; my $root_link = base_path('link'); $text =~ s/$root_link\///; # removes the $ro +ot_link $text =~ s/_/ /g; # removes underso +res $text =~ s/ (Mr|Mrs|Ms|Dr) / $1. /g; # adds a period f +or Mr, Mrs, Ms, and Dr; I may need to add more $text =~ s/\s&\s/ &amp; /g; # converts ' & ' +to &amp; $text =~ s/\.{3}/&#8230;/g; # converts '...' +to &#8230; $text =~ s/(\w|\b|\s|^)'(\w|\b|\s|$)/$1&#700;$2/g; # converts "'" to + &#700; # The following takes out html tags unless I tell it not to $text =~ s/<.+?>//g unless ($opt->{'html'} && $opt->{'html'} + =~ /^[ytk1]/); # The following takes out parenthes unless I tell it not to $text =~ s/\s\(.*?\)$// unless ($opt->{'parens'} && $opt->{'parens' +} =~ /^[ytk1]/); # The following removes file extensions except .com, .net, and .org $text =~ s/\.\w{2,5}?$// unless $text =~ /\.(?:com|net|org)$/; # $text =~ s/(?<!\A)((?<! )\p{uppercase})/ $1/g; # from Kenosis, kcot +t, and tye on PerlMonks # I could not remember what the previous line was doing. return $text; }

      My OS is Debian 10 (Buster); my perl version is 5.28.1.

      No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
      Lady Aleena

        You've only provided snippets of code which has proven problematic. For instance, you have

        my $root_link = base_path('link');

        but don't show the &base_path code. Is it from a module? Did you write it?

        You also have several lines of code like these:

        my $magic = crossover_magic( big => ['Horror']); my $magic = crossover_magic( big => ['Westerns in Crisis']);

        but don't show any context. Are those strings hard-coded as shown? They actually look like return values from textify(). It's also unclear what the comments about preferences mean; for example, what does "# I'd like to use the word 'Westerns' only" refer to? — why not just write 'Westerns' instead of 'Westerns in Crisis'?

        And then there's the array @cross_files whose value you show as an arrayref. Next to it is textified which should probably be $textified if its value is also an arrayref.

        The end result of this is a lot of guesswork and assumptions which are not helpful in providing you with a straightforward answer.

        I put together an SSCCE to test all the possible things that I think you might be doing: it's in the spoiler below. The output is hundreds of lines long so I won't post it here: it should run without any problem with the OS and Perl version you indicated.

        I couldn't replicate "Everything is getting  right appended currently." as you stated in the OP. In fact, I got the expected output for everything except when filenames contained underscores.

        Reviewing what I've provided may help you to solve your problem. If not, please write your own SSCCE and post it. Use only sufficient sample data to demonstrate the issue and do not include code that isn't relevant to the problem: it should only be enough to demonstrate whatever is going wrong.

        Here's my SSCCE (in the spoiler):

        — Ken

Re: How do I get an exclusion with grep?
by AnomalousMonk (Bishop) on Apr 27, 2020 at 05:58 UTC
    ... I do not want right appended to $class if Smart is in $text.

    Your code seems to me to do what you want.

    c:\@Work\Perl\monks>perl -wMstrict -le "my @big_images = qw(xsMaRty Dull Boring); ;; my $text = 'Smart'; ;; my $class = 'svg_group'; $class .= ' right' unless grep(/$text/i, @big_images); ;; print qq{'$class'}; ;; $text = 'Xxx'; ;; $class = 'svg_group_2'; $class .= ' left' unless grep(/$text/i, @big_images); ;; print qq{'$class'}; " 'svg_group' 'svg_group_2 left'
    In the first case, Smart is in $text and right is not appended. In the second case, Smart is not in $text and left is appended.

    Update: You may also be interested in any and none in List::Util.


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

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2020-08-13 00:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which rocket would you take to Mars?










    Results (68 votes). Check out past polls.

    Notices?