http://www.perlmonks.org?node_id=11112124

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

I am making a program that reports about what scripts have certain values in them so i can read them more easy. This is going quite well except when i look for values that start with a $ sign except for a bear $ sign. There are hundreds of programs that have something like $text or $file in them and my program just can't find them. So when i test the following program for f.e. $mw it won't find it. I have added the entire script.

use Tk; use strict; use warnings; my $mw = MainWindow->new(); my $frame = $mw->Frame->pack; my $label = $frame->Label(-text=>"searchvalue?")->pack(-side=>'left',- +anchor=>'n',-padx=>20,-pady,10); my $entry = $frame->Entry()->pack(-side =>'left',-anchor=>'n',-padx=>2 +0,-pady=>10); my $but = $frame->Button(-text=>'go and look',-command => \&go )->pack +(-side =>'left',-anchor=>'n',-padx=>20,-pady=>10); my $lb = $frame->Scrolled("Listbox", -scrollbars => 'e'); $lb->configure(-width=>50); $lb->pack(-side=>'left',-anchor=>'n',-padx=>20,-pady=>20); my $text = $mw->Scrolled("Text", -scrollbars => 'e')->pack(-side=>'bot +tom',-anchor=>'w',-padx=>20,-pady=>10); $lb->bind('<Button-1>',\&search); MainLoop; sub search{ my $index = $lb->curselection; my $bestand = $lb->get($index); $text->delete('0.0','end'); open(my $fh,"<",$bestand)|| die $!; while(my $lin = <$fh>){ $text->insert('end',$lin); }; close $fh; } sub go{ $lb->delete(0,'end'); my $zoek = $entry->get; my $dir = "C:/codes"; opendir(my $dh,$dir); while(my $file = readdir($dh)){ if(-f "$dir/$file"){ open(my $fh,"<",$file) || die $!; while(my $line = <$fh>){ if($line =~ /$zoek/){ $lb->insert('end',"$dir/$file"); last; } } close $fh; } } close $dh }

Maybe some knows about this issue.Tx.

Replies are listed 'Best First'.
Re: program cant find values that start with $
by tybalt89 (Parson) on Jan 30, 2020 at 18:44 UTC

      Thank you.

Re: program cant find values that start with $
by BillKSmith (Prior) on Feb 01, 2020 at 14:13 UTC
    Your original code gives the user the full power of regular expressions. When he intends a literal dollar sign, he has to escape it himself. The \Q...\E solution restricts him to literal character searches. From a security viewpoint, this restriction is a huge benefit. Casual users will not mind the restriction, in fact most will appreciate the convenience it provides.
    Bill
Re: program cant find values that start with $
by Anonymous Monk on Jan 31, 2020 at 14:22 UTC

    Thanks for replying everyone.

Re: program cant find values that start with $
by sundialsvc4 (Abbot) on Jan 31, 2020 at 02:13 UTC

    Although I haven’t personally tested it, might not the \Q...\E business be a bit too extreme? Would not a simple backslash \$ been sufficient here?

    (No ... nevermind who I am ... this is a serious question ...)

      Two different things!

      Escaping the dollar means that variable interpolation won't happen and only literal '$zoek' can match.

      quotemeta on the other hand escapes regex metas after inserting the content of $zoek

      "zoek" is Dutch for "search" and is literal user input via Tk. But a $ in input is also a meta which needs to be quoted.

      main::(-e:1): 0 DB<1> $x='.' DB<2> p 'a' =~ /$x/ 1 DB<3> p 'a' =~ /\Q$x/ DB<4> p '.' =~ /\Q$x/ 1 DB<5> p '.' =~ /$x/ 1 DB<6> p '.' =~ /\$x/ DB<7> p '$x' =~ /\$x/ 1 DB<8>

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        Another way to look at this is via the stringization of qr//:

        c:\@Work\Perl\monks>perl -wMstrict -le "my $x = '.'; print for qr{$x}, qr{\Q$x}, qr{\$x}, 'etc...'; " (?-xism:.) (?-xism:\.) (?-xism:\$x) etc...


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

      There are two different layers of processing here. First, Perl applies the standard interpolations for double-quoted ("qq") strings to get a regex. Second, Perl interprets the string it produced in the first step as a regex.

      The $ character is special in both of these contexts: in qq-string interpolation it introduces a variable substitution and in a regular expression (from which Perl regexes inherit their basic features) it is a special atom matching "end of line". The problem in this program is that we need to interpolate a string obtained from Tk such that when the user enters "abc$def", the regex engine will actually match that exact string, so we need the first step to produce 'abc\$def' with a backslash to escape the $ character. This is what quotemeta does, and using "\Q$foo\E" is shorthand for my $tmp = quotemeta $foo; and "$tmp" but probably more efficient.

      A simple \$ prevents the interpolation in the first step. Using "\$foo" happens to be equivalent to '$foo', which would be a fixed search pattern and unlikely to be useful in the questioner's program.

      Another option would be to document that the program accepts regexes instead of fixed strings and require the user to enter 'abc\$def' if a match for the literal string 'abc$def' is desired.