Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options

How can grep search based on text or pattern based on user input?

by Russ (Deacon)
on Dec 02, 2000 at 08:11 UTC ( #44553=perlquestion: print w/ replies, xml ) Need Help??
Russ has asked for the wisdom of the Perl Monks concerning the following question:

This was moved from Categorized Questions and Answers.
Please do not vote for this node. It will affect the wrong user.
Thank You -- Q&AEditors

I've got a CGI that accepts a single form field (name=searchtext) which I put into $searchtext. I'd like to offer the un-Perl-knowledgeable user to simply enter a word with * wildcards like any normal search, but at the same time offer the Perl-knowledgeable user the ability to enter a pattern.

I'm assuming that the un-Perl will enter something like "surf*g" and the Perl user will enter something like "/surf\w*/i" or similar. (I'm assuming that all searches by the un-Perl are case insensitive.)

Here's what I have so far:

if ($searchtext =~ /^\/.*\/\w+$/) { $searchtext =~ s#^\s+/|/\s+$|/\w+\s+$#/#g; } else { $searchtext =~ s/([\\\+\$\^])/\\$1/g; $searchtext =~ s/\*/\\w\*/g; $searchtext = '/' . $searchtext . '/i'; } foreach (sort {$a <=> $b} grep $searchtext, grep !/^#/, <STUFF>) {

Problem is, this doesn't work. And even if it did, I'm sure it's nowhere close to being the most efficient code around. Any suggestions? Thanks. :)

Replies are listed 'Best First'.
Re: How can grep search based on text or pattern based on user input?
by chromatic (Archbishop) on Dec 02, 2000 at 08:21 UTC
    A regex (or the left hand side of a substitution) performs interpolation on any variables inside, a la:

    foreach (sort {$a <=> $b} grep /$searchtext/, grep !/^#/, <STUFF>) {

    That means that you'll have to strip off the slashes on a user-supplied regex, and not add them in on the other option.

    As for efficiency, it's not too bad. I'd get rid of the double grep though, by slurping everything in at once (if it's a small file), skipping commented lines, or rewriting the loop condition somewhat.

      First off, thanks all for your previous help.

      OK, while I know a radio button would be easiest for this solution, I'm fairly confident that most of my users will just get confused. But I still want to offer the extra ability to those wise few. (Besides, this is a fun little learning project.) So I need to just do everything auto-magicly. If I can't remove the "/"s from the grep line, can I do something like:

      grep /$searchtext/$modifiers @stuff

      Problem is, I'm reasonably sure this will not work. I also am nervous about this not being able to handle any regex the highly-skilled user may input. Essentially, I'm looking at getting the following to work:

      @stuff = ('This is some text.','This is more text.'); $stext = '/some/i'; ($null, $text, $mod) = split(/\//, $stext); foreach (grep /$text/$mod, @stuff) { print $_, "\n"; }

      Can anyone get this to work? BTW, please tell me if I'm being an annoying-newbie, and I'll go away.

        Removing the slashes is pretty easy. Here's one (non-optimal) attempt:

        $input =~ s!^/(.+)/$!$1!;

        With that in place, everything you've described so far, except for the $modifiers, will work. You'd either have to escape everything and wrap the whole grep in an eval block, or use some sort of checkbox or if-else block to check for a case insensitive flag.

        Perl won't (as far as I know, and I'm pretty sure about this having just tested it) interpolate a variable in the regex flag position.

Re: How can grep search based on text or pattern based on user input?
by dchetlin (Friar) on Dec 04, 2000 at 11:44 UTC
    `grep' in Perl is a misnomer; it's not inherently related to RExen. It should really be named `filter' or something similar. As such, using a bare variable as the `EXPR' in grep EXPR, LIST won't invoke the REx engine at all -- basically you're checking $searchtext for truth each time through the `LIST', which is most certainly not WYM.

    My personal vote on this problem would be to provide the users a radio button group allowing them to choose whether they want to use Perl-based or standard search-engine searches, rather than trying to come up with a heuristic to determine if $searchtext is a Perl REx or just a term.

    However, if you really want to do that, you'll want to look into `\Q' and `\E' to quote characters in a REx, rather than going to all that trouble (on line 4) to take care of metacharacters. I'm skeptical of the conversion from `*' to `\w*', but I suppose it's a sensible choice.

    Rather than trying to build up a string that syntactically resembles a REx in Perl code, build the actual search pattern and then use it in the grep inside of a REx:

    grep m/$searchtext/, <STUFF>

    You might also want to look into qr// for a more efficient and cleaner way to build RExen programatically.


Log In?

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

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (15)
As of 2016-06-28 14:39 GMT
Find Nodes?
    Voting Booth?
    My preferred method of making French fries (chips) is in a ...

    Results (359 votes). Check out past polls.