1

I'm new to programming much less Perl; I'm having difficulty with searching an array I've made from an external text file. I'm looking for a simple way to check if the user entry is located in the array. I've used the Smart Match function before but never in an "if" statement and can't seem to get it to work. Am I implementing this function wrong, or is there an easier way to check if the user's string is in the array?

#!/usr/bin/perl
use 5.010;
#Inventory editing script - Jason Black
#-------------------------------------------------------------------------------
print "1. Add Items\n";
print "2. Search Items\n";
print "Please enter your choice: ";
chomp ($userChoice = <STDIN>); #Stores user input in $userChoice

if($userChoice == 1){
    $message = "Please enter in format 'code|title|price|item-count'\n";
    &ChoiceOne;
}

elsif($userChoice == 2){
    $message = "Enter search terms\n";
    &ChoiceTwo;
}

sub ChoiceOne{
print "$message\n";
chomp($userAddition = <STDIN>); #Stores input in $userAddition
$string1 = "$userAddition";
open (FILE, "FinalProjData.txt") or die ("File not found"); #"FILE" can be named anything
@array = <FILE>;

if ( /$string1/ ~~ @array){
print "This entry already exists. Would you like to replace? Y/N \n";

chomp($userDecision = <STDIN>); #Stores input in $userDecision
    if ($userDecision eq "Y"){  
        $string1 =~ s/$userAddition/$userAddition/ig;
        print "Item has been overwritten\n";}
    elsif($userDecision eq "N"){ 
        print FILE "$string1\n";
        print "Entry has been added to end of file.\n";}
    else{
        print "Invalid Input";
        exit;}

    }
else {
    print FILE "$string1\n";
    print "Item has been added.\n";}

close(FILE);
exit;
}#end sub ChoiceOne

sub ChoiceTwo{
print "$message\n";

}
Bennett
  • 585
  • 1
  • 12
  • 24
  • It says [here](http://perldoc.perl.org/perlop.html#Smartmatch-Operator) that the smartmatch behaves differently in perl 5.10.0 and is only officially available (experimentally) in perl 5.10.1. Perhaps `use 5.10.1`? – Kenney Dec 07 '15 at 19:14
  • 2
    Obligatory FYI...[smartmatch was made experimental in 5.18.0](http://perldoc.perl.org/perl5180delta.html#The-smartmatch-family-of-features-are-now-experimental): "It is clear that smartmatch is almost certainly either going to change or go away in the future. Relying on its current behavior is not recommended." It [sounds like](http://markmail.org/message/u22titrq5ljclz4b) changes are in the works, so it probably won't be removed, but I wouldn't use it until those are solidified. – ThisSuitIsBlackNot Dec 07 '15 at 19:16
  • @Kenney `use 5.010` doesn't actually change the version of the interpreter being used; it just throws an exception if the version is < 5.10.0. – ThisSuitIsBlackNot Dec 07 '15 at 19:21
  • @ThisSuitIsBlackNot Ah I see, thanks! I did think it would at least make sure that the v5.10.1 (and later) implementation was required. – Kenney Dec 07 '15 at 19:23
  • One thing I do see is that you are `chomp`ing the user input but not the `` lines. But `~~` or unanchored `grep` shouldn't care. The other thing is that your "replace" doesn't seem to be doing anything (same lhs and rhs in `s///`). – Jeff Y Dec 07 '15 at 19:28
  • I'm surprised there are still tutorials out there that tell you to use an ampersand on a subroutine call. `&ChoiceOne` etc. Is nearly twenty years out of date. `ChoiceOne()` has been correct since the arrival of Perl version 5.5. And you should also `use strict` and `use warnings 'all'` at the top of every program you write, and avoid capitals in local identifiers, so `$user_choice` and `choice_one()` – Borodin Dec 07 '15 at 21:49

1 Answers1

6

If you want to avoid using smartmatch alltogether:

if ( grep { /$string1/ } @array ) {

To actually match the $string1, however, it needs to be escaped, so that | doesn't mean or:

if ( grep { /\Q$string\E/ } @array ) {

or just a simple string compare:

if ( grep { $_ eq $string } @array ) {
Kenney
  • 9,003
  • 15
  • 21
  • 5
    Avoid smartmatch is good because it's an experimental feature that's likely to change. – ikegami Dec 07 '15 at 19:22
  • 4
    I prefer `any` from [List::Util](http://perldoc.perl.org/List/Util.html#any) since it will stop searching the list as soon as a match is found. – ThisSuitIsBlackNot Dec 07 '15 at 19:25
  • 2
    Also, the OP's regex is unanchored so this can match elements that are not equal to `$string1`. They probably want `$_ eq $string1` (although they'll also need to `chomp @array;`). – ThisSuitIsBlackNot Dec 07 '15 at 19:27
  • @TSIBN In which case he had better `chomp` into `@array` as well (since he has `chomp`ed `$string1`). – Jeff Y Dec 07 '15 at 19:29
  • If speed were the issue I'd just read the entire file as a scalar and `if ( index( $filecontents, $string1 ) >= 0 )` – Kenney Dec 07 '15 at 19:31
  • @Kenney With this I'm getting same result. It tells me what I'm trying to add is in the text file even though it isn't. Also I added a chomp into array. – Bennett Dec 07 '15 at 21:04
  • Perhaps it is. Did you consider that your input `foo|bar|baz` actually means `foo OR bar OR baz` in a regexp context? ;-) Btw, you're not updating or saving the file anywhere. There's no code for that anywhere. The closest you come is `$string1 =~ s/$userAddition/$userAddition/ig;` which does effectively nothing (except perhaps change the case of some letters). – Kenney Dec 07 '15 at 21:07