in reply to Re: help with user selected hash operations?
in thread help with user selected hash operations?

i've definitely solved the repetition problem! i'm not sure i can /see/ what "next;" is doing, but it does seem to be helping! haha.

i think my confusion now is, after doing all the other steps i can, i'm still not positive how to make the final if statement work: it's meant to be, "if user inputs none of the menu options, the invalid message appears". when i had it set to "if ($choice ne 'a'...'e')" then print the error message, but it seems like it's taking the input for $name1, etc, as an invalid input, too.

} if ($choice eq 'r'){ print "Enter a male name: "; chomp (my $name3 = lc <STDIN>); if (exists $son_father{$name3}) { print "Enter a new father name: "; chomp ($newname = <STDIN>); $son_father{$name3} = {$newname}; } else { print "Sorry, couldn't find you -- try again later!"; next; } } if ($choice ne 'a', 'r', 'o', 'd', 'e') { print "Invalid choice, TRY AGAIN!\n"; } }

i'm going to try and ask my professor about this more tomorrow, but i'm wondering if i'm just missing something obvious. will it read /every/ non-$choice standin as false if i write the if statement like this? is there any way to fix that? i thought assigning each standin a different variable would keep it separate from the if statement...

i'm definitely feeling less anxious after getting some help, but i'm getting pretty delirious after working on this for seven hours, hahah. sorry for being a bit incoherent.

oh, gosh, i forgot to say thank you. that's the problem with staying up until 4am. thank you so much!

Replies are listed 'Best First'.
Re^3: help with user selected hash operations?
by holli (Abbot) on Oct 30, 2017 at 09:07 UTC
    if ($choice ne 'a', 'r', 'o', 'd', 'e') { print "Invalid choice, TRY AGAIN!\n"; }
    No, conditions don't work that way. You cannot have a list of options on the right hand side of an eq.
    Possible solutions:
    # Very explicit: if ($choice ne 'a' && $choice ne 'r' && $choice ne 'o' && $choice ne ' +d' && $choice ne 'e') { print "Invalid choice, TRY AGAIN!\n"; } # Testing if the element is in a List of options: unless ( grep { $_ eq $choice } ('a', 'r', 'o', 'd','e') ) { print "Invalid choice, TRY AGAIN!\n"; } # Testing if the element matches a regular expression: unless ( $choice =~ /^(a|r|o|d|e)$/ ) { print "Invalid choice, TRY AGAIN!\n"; }


    holli

    You can lead your users to water, but alas, you cannot drown them.
      You can also use a character class in a regex:
      unless ($choice =~ /^[arode]$/) {

      Also, some people prefer List::Util::none to negated grep:

      use List::Util qw{ none }; if (none { $_ eq $choice } qw( a r o d e )) {
      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      okay, i thought it was something like that. the problem with working on code so long is after a while you just throw stuff at the wall and see what sticks.

      and thank you! i was trying to understand the "unless" condition last night but i think my brain was just scrambled. that makes sense!

        lunette:

        Heh, while I understand the frustration, "throwing stuff at the wall and seeing what sticks" is a terrible habit for a programmer. It's like going to a foreign country and speaking your native language slowly and loudly in an attempt to be understood by the locals.

        Rather than making an uninformed guess as to why your program is doing something strange, try running the code under the debugger and executing through it line by line. That way, if your if statements are nested incorrectly, you'll see it happen. Also, while you're in the debugger, you can ask perl what the value of a variable is, so you can see what's happening and give you important clues as to what the problem actually is. Once you identify the true problem, often the fix is really simple.

        For example, let's start running your code as found in Re^2: help with user selected hash operations? under the debugger (using the -d flag). First, let's start it up:

        $ perl -d pm_1202351.pl Loading DB routines from perl5db.pl version 1.49_001 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. main::(pm_1202351.pl:4): my %son_father; DB<1>

        OK, perl started up, and told us how to get help for the debugger commands, and showed us the next line it wants to execute, specifically line 4 (my %son_father;). It then prompts us (DB <1>) telling us it's ready to accept a command. I've already looked over your program, so we won't tediously execute each and every line. Instead, we'll tell perl to continue running until just after it accepts your first menu choice. The if statement after that is line 41, so we'll tell perl to run until it gets to line 41 (c 41) then we'll ask it to display the value of $choice (p $choice):

        DB<1> c 41 SON_FATHER Hash Operations a- Add a son-father pair d- Delete a son-father pair e- exit the program g- Get a father o- Output the hash neatly r- Replace a father x- get a grand father Make your choice: g main::(pm_1202351.pl:41): if ($choice eq 'a'){ DB<2> p $choice g

        Good, it holds 'g', just as expected. Obviously, it's not going to match 'a', so if we execute the next line, we expect that the program will skip over the whole if statement, and wind up on line 53, the if statement for the next choice (if ($choice eq 'd') {. Let's see what happens:

        DB<3> n main::(pm_1202351.pl:44): } if (exists $son_father{$name1} +) { DB<3>

        Nope! The next statement is line 44. See the closing curly at the beginning of the line? That's the matching curly for the one at the end of line 41. Your indentation shows that you want line 44 to be inside the if statement on line 41, but your curly braces tell perl otherwise. (Perl looks at the curly braces, and doesn't care a whit about whitespace. The whitespace is just to help programmers understand the code structure.)

        So we'll quit the debugger, and change from:

        if ($choice eq 'a'){ print "Enter a male name: "; chomp (my $name1 = ucfirst lc <STDIN>); } if (exists $son_father{$name1}) { print "Duplicate name -- try again!\n"; } else { print "Add a father: "; chomp (my $add_dad = ucfirst lc <STDIN>); $son_father{$name1} = {$add_dad}; next; }

        to this:

        if ($choice eq 'a'){ print "Enter a male name: "; chomp (my $name1 = ucfirst lc <STDIN>); if (exists $son_father{$name1}) { print "Duplicate name -- try again!\n"; } else { print "Add a father: "; chomp (my $add_dad = ucfirst lc <STDIN>); $son_father{$name1} = {$add_dad}; next; } }

        Now, let's try again:

        $ perl -d pm_1202351.pl Loading DB routines from perl5db.pl version 1.49_001 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. main::(pm_1202351.pl:4): my %son_father; DB<1> c 41 SON_FATHER Hash Operations a- Add a son-father pair d- Delete a son-father pair e- exit the program g- Get a father o- Output the hash neatly r- Replace a father x- get a grand father Make your choice: g main::(pm_1202351.pl:41): if ($choice eq 'a'){ DB<2> p $choice g DB<3> n main::(pm_1202351.pl:54): if ($choice eq 'd') {

        Success! This time, it successfully skipped the first choice, and is now checking whether we selected 'd'. Let's run the next statement, and...

        DB<3> n main::(pm_1202351.pl:57): } if (exists $son_father{$name2} +) {

        Oops! Did it again.

        As you can see, running the code under the debugger is pretty simple. Just press 'h' to get a list of available commands:

        DB<1> h List/search source lines: Control script execution: l [ln|sub] List source code T Stack trace - or . List previous/current line s [expr] Single step [in +expr] v [line] View around line n [expr] Next, steps over + subs f filename View source in file <CR/Enter> Repeat last n or + s /pattern/ ?patt? Search forw/backw r Return from subr +outine M Show module versions c [ln|sub] Continue until p +osition Debugger controls: L List break/watch +/actions o [...] Set debugger options t [n] [expr] Toggle trace [m +ax depth] ][trace expr] <[<]|{[{]|>[>] [cmd] Do pre/post-prompt b [ln|event|sub] [cnd] Set b +reakpoint ! [N|pat] Redo a previous command B ln|* Delete a/all bre +akpoints H [-num] Display last num commands a [ln] cmd Do cmd before li +ne = [a val] Define/list an alias A ln|* Delete a/all act +ions h [db_cmd] Get help on command w expr Add a watch expr +ession h h Complete help page W expr|* Delete a/all wat +ch exprs |[|]db_cmd Send output to pager ![!] syscmd Run cmd in a sub +process q or ^D Quit R Attempt a restar +t Data Examination: expr Execute perl code, also see: s,n,t expr x|m expr Evals expr in list context, dumps the result or lists + methods. p expr Print expression (uses script's current package). S [[!]pat] List subroutine names [not] matching pattern V [Pk [Vars]] List Variables in Package. Vars can be ~pattern or ! +pattern. X [Vars] Same as "V current_package [Vars]". i class inherita +nce tree. y [n [Vars]] List lexicals in higher scope <n>. Vars same as V. e Display thread id E Display all thread ids. For more help, type h cmd_letter, or run man perldebug for all docs.

        I generally use very few of these commands. I mostly use:

        • c # - to execute code up to the specified line number
        • n - to execute the line the debugger showed just before the prompt until the next line number. This will skip over subroutines.
        • s - Execute until we get to another line of code. If the current line calls a subroutine, then you'll wind up inside it. When you get familiar with c, n and s, you can navigate through your code fairly quickly.
        • p - to print an expression (This is pretty nice, as it's just like the print statement in your program, so you can do things like:
          DB<3> p "FOO! <$choice>\n" FOO! <g> DB<4>
        • x - to look at a data structure and dump its contents (hashes are printed as keys on the even lines, values on the odd lines):
          DB<4> x %son_father 0 'Bruce' 1 'Richard' 2 'Robert' 3 'Jason' 4 'Clark' 5 'Jon' 6 'Jeff' 7 'Doug' 8 'Thomas' 9 'Evan'
        • v # - show the source code around a particular line number:
          DB<6> v 50 47: print "Add a father: "; 48: chomp (my $add_dad = ucfirst lc <STDIN>); 49: $son_father{$name1} = {$add_dad}; 50: next; 51 } 52 } 53 54: if ($choice eq 'd') { 55: print "Enter a male name: "; 56: chomp (my $name2 = ucfirst lc <STDIN>);
        • r - continue executing code until we return from the current subroutine.

        I'd consider that my "minimum set" of debugger commands. As you get more familiar with perl, you'll want to learn more of the debugger commands so you can get even faster at figuring out what's happening. (Breakpoints and watch expressions are very nice!)

        To start off, I'd suggest running your program in the debugger, and just use the s command to execute step-by-step, and using p and x to examine variables. You'll get a feel for things pretty quickly, and you won't have to guess what your program is doing, you'll be able to watch it in as much detail as you want.

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

Re^3: help with user selected hash operations?
by holli (Abbot) on Oct 30, 2017 at 08:55 UTC
    i'm not sure i can /see/ what "next;" is doing
    for ( 1 .. 3 ) { print "The father\n"; print "The son\n"; next; print "But no holy ghost\n"; }
    Do you see it now? You do really need to understand the core concepts, like loops, if's and most importantly true/false. If you don't: this happens. I'm all for learning by example - this is the natural way our brain works - but you need examples of one core concept at a time.


    holli

    You can lead your users to water, but alas, you cannot drown them.
      yes!! this is very easy to understand, thank you!! i understand now.
Re^3: help with user selected hash operations?
by hippo (Archbishop) on Oct 30, 2017 at 09:28 UTC

    In addition to the other excellent advice you have received, I will offer a diagnostic tool which is as useful as it is simple: don't just say something's wrong, say in what way it is wrong. ie. instead of

    print "Invalid choice, TRY AGAIN!\n";

    do this:

    print "Invalid choice ($choice), should be one of a, r, o, d or e. TRY + AGAIN!\n";

    This will let you know either that your condition is badly written (as it was) or if $choice is not being correctly set.

    For other handy tips, do peruse the Basic debugging checklist.