Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

regex help needed

Status
Not open for further replies.

ejaggers

Programmer
Feb 26, 2005
148
US
'report' =~ /$input/;
will match $input = 'r', 're',...'report'.

I need a quantifer like {MIN,} for cases like:
'report' =~ /$input/;
'resolve' =~ /$input/;

But I don't know how to use a quantifer on a variable.
i.e /$input{MIN,MAX}/. Can this be done some kind of way?
 
Isn't your regex backwards?
$input =~ /report/;
?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those who say it cannot be done are usually interrupted by someone else doing it; Give the wrong symptoms, get the wrong solutions;
 
$input{MIN,MAX}" would be interpreted as something to do with associative arrays in Perl, because Perl would think the curly brackets have something to do with the variable itself and not the regular expression.

So put the variable itself in curly brackets so it doesn't mess with its surroundings.

Code:
/${input}{2,4}/

(I substituted MIN/MAX with 2/4 here, they could be variables too if ya had them as like $min/$max or whatever. probably not constants though).

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
Isn't your regex backwards?
$input =~ /report/;
?

While I don't know if he has it backwards, it is OK to write a regexp like that.

Code:
my $input = 'r';
if ('report' =~ /($input)/) {
   print $1;
}

Although generally we don't see this type of usage.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
[1] >[tt]/${input}{2,4}/[/tt]
That seems to mean only "consecutive" such as r in 'error'.

[2] I would say, maybe, this.
[tt]
my $input = 'r';
if (($count=()='error'=~/($input)/g) && $count >=2 && $count<=4) {
print 'error:eek:k'."\n";
}

if (($count=()='resolve'=~/($input)/g) && $count >=2 && $count<=4) {
print 'resolve:eek:k'."\n";
}

if (($count=()='error report'=~/($input)/g) && $count >=2 && $count<=4) {
print 'error report:eek:k'."\n";
}
[/tt]
[2.1] Risk to squeezing into one-liner, it suppose the min max is nonzero. Otherwise, just take the $count outside the conditional or make $count inflated by one (1) for instance.
 
tsuji,

I'm trying to distinguish between ‘report’ and ‘resolve’. These are input commands from the user. But you changed the command to ‘error report’, which is an invalid user input. However, the following works, but I thought someone could tell me how to do it using a regex:

my $count = length($input);
if ( 'report' =~ /^$input/ && $count > 2 ) { sub1() };
if ( 'resolve' =~ /^$input/ && $count > 2 ) { sub2() };

BTW, please explain this: $count=() in the above solution.

And you are right, /${input}{2,4}/ does not work.
 
[3] I am not quite sure you now count the length of $input, rather than testing if the input pattern match the target string ('report' or 'resolve') at multiple instance. Furthermore, anchor it to the start of the string would not be conducive to set up multiple instance case (or /g flag).

[4] Suppose I visualize $input be r and intend to distinguish 'report' from 'resolve', it would be this with your two conditional lines.
[tt]
if (($count=()='report'=~/($input)/g) && $count >1) {sub1()};
if (($count=()='resolve'=~/($input)/g) && $count >1) {sub2()};
[/tt]
I would say there if $input be 'r', sub1 would be executed and sub2() won't.

[5] () idiom is explained here, certainly better than I explaining.
 
if the user input is report or resolve and nothing else maybe you want to use a string comparison operator:

Code:
if (lc($input) eq 'report') {
   ...
}
elsif (lc($input) eq 'resolve') {
   ...
}
else {
   ...
}

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
KevinADC,

No the user input can be: r, re, rep, repo, repor, or report.

That's why r, re are a problem. They only have to type enough of the command to make it unique.
 
I would go with this approach for that then.

Code:
$| = 1;
print "> ";
chomp (my $input = <STDIN>);
for ($input) {
   /^rep/i && do { # report
      print "you typed report\n";
      last;
   };

   /^reg/i && do { # register
      print "you typed register\n";
      last;
   };

   /^re?/i && do { # r or re
      print "type more to make it unique.\n"
        . "you might've meant: report, register\n";
      last;
   };

   print "unknown command\n";
}

Ex output:

Code:
[kirsle@firefly ~]$ perl test2
> reg
you typed register
[kirsle@firefly ~]$ perl test2
> register
you typed register
[kirsle@firefly ~]$ perl test2
> rep
you typed report
[kirsle@firefly ~]$ perl test2
> reporttt
you typed report
[kirsle@firefly ~]$ perl test2
> r
type more to make it unique.
you might've meant: report, register
[kirsle@firefly ~]$ perl test2
> re
type more to make it unique.
you might've meant: report, register

Would something like that work? Have your regexps always match the minimum unique part of the command and have a comment next to it so you know what the "proper" name of the command is.

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
Fore!

Code:
my @commands = qw(
        register
        report
        read
        rar
        right
);
$| = 1;
while (1) {
        print "Command> ";
        chomp (my $cmd = <STDIN>);

        # try to find matching commands.
        my @matches = ();
        foreach my $c (@commands) {
                if ($c =~ /^\Q$cmd\E/i) {
                        push (@matches, $c);
                }
        }

        # only one match?
        if (scalar(@matches) == 1) {
                print "MATCH! You typed: $matches[0]\n";
        }
        elsif (scalar(@matches) == 0) {
                print "** NO MATCHES AT ALL **\n";
        }
        else {
                # Many matches
                print "MANY MATCHES FOUND! Did you mean:\n"
                        . join("\n",@matches) . "\n\n";
        }
}

Code:
[kirsle@firefly ~]$ perl test3
Command> r
MANY MATCHES FOUND! Did you mean:
register
report
read
rar
right

Command> re
MANY MATCHES FOUND! Did you mean:
register
report
read

Command> register
MATCH! You typed: register
Command> test
** NO MATCHES AT ALL **
Command> ra
MATCH! You typed: rar
Command> ri
MATCH! You typed: right
Command> r
MANY MATCHES FOUND! Did you mean:
register
report
read
rar
right

Command> re
MANY MATCHES FOUND! Did you mean:
register
report
read

Command>

:)

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
Kirsle,

I've use your approach when writing a full command processor routine, to asked which cmd to use. But my original situation was much smaller. It either matches or not, but doesn't try to fiqure out what the user meant.

tsuji (TechnicalUser)'s approach of counting for a minimun number of begins-with letters probably the best solution, but I like the way you think.
 
That's why r, re are a problem. They only have to type enough of the command to make it unique.

Since your overall requirements are not clear its hard to say how you should go about it. If a person enters a value that is not unique enough I would just continue to kick back a message alereting the user to coninue entering more charcters until your script can be sure what the user wants to do.

This seems to vague to me:

Code:
if (($count=()='report'=~/($input)/g) && $count >1) {sub1()};
if (($count=()='resolve'=~/($input)/g) && $count >1) {sub2()};

If the user inputs 'r' there is little reason to assume they meant "report" instead of "resolve". Then again, it may be unimportant for all I know. And if they enter "re" nothing will run. Of course I realize the code is only an example, maybe not meant as a solutionto anything really.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
KevinADC (TechnicalUser),

Sorry, I thought my requirement were clear:
the user must type enough chars to distingish which command to use. For instance, with 'report' and 'resolve', as stated above, the user must type at the least 'rep' for report, or 'res' for resolve.

This is my solution:
$count = length($cmd);
if ( $count > 2 && 'report' =~ /^$cmd/ ) {do something}
if ( $count > 2 && 'resolve' =~ /^$cmd/ ) {something else}

My original question was, "can you tell a regex that $cmd has to be a minimum (in this case) of 3 chars to match?"

My solution works fine and is very simple, however, my question was basically out of curiosity and learning, rather than need.
 
Kirsle (Programmer),

Why did you do this: $| = 1;
 
OK. I guess I wasn't paying close enough attention. That does clear it up.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
The code "$| = 1" turns on (or off?) the output buffering. By default $| is 0 and if you print text to the terminal, it won't appear until a newline character is sent.

Demonstration:

Code:
print "Default behavior:\n";
&hello();

print "Setting that variable:\n";
$| = 1;
&hello();

sub hello {
   my @str = split(//, "Hello world!");
   foreach (@str) {
      print;
      sleep 1;
   }
   print "\n";
}

Running that should say "Default behavior:" and then pause for about 12 seconds then say "Hello world!" all at once, then it'll say "Setting that variable:" and then "type out" "Hello world!" one character at a time.

Because a "\n" isn't printed until the very end, the entire line of output isn't written to the terminal in the first case.

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top