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

Hey again, folks! Before I get to my real question, which relates to this non-working as I expected regex I came up with:

$phr =~ s/\s+(w+)\s+(w+)/$2\s+$1;

I would just like to say how much I'm LOVING this site! Learning much more than I ever expected! I'm just having a freakin' BLAST learning this stuff and getting the best feedback I've EVER gotten during a learning process! I wish that I had something analagous to this site back when I was learning C and C++!!! I would deem this process far superior to the classes I had for C (I had already taught myself some C++ by that point!) at NYU! No comparison, in my mind. This educational experience has been better than that. Okay, I'm done kissin' up to you schlubs! ;D Onto the matter at hand!

The problem I'm struggling with comes from exercise 2 p.272 in Lemay's Book. Although, as I pointed out earlier I fully intend on reading merlyn's book. By the way, curious, but which author is merlyn? Randall or Tom? I digress. Okay, now, I'm really ready! :)

The problem states that one must

----------------------------------------------------
2. Write a subroutine that takes a string as an argument and returns the string in reverse order by words.
----------------------------------------------------

#!/usr/bin/perl -w use strict # okay! okay! I give! uncle! (even though I still don't kno +w what it does yet! :) initargs(); # thanks for teaching me the more modern perl convention. +Lemay's book is a bit dated. print "\nPlease enter a phrase: "; chomp ($phr = <STDIN>); rev($phr); print "\n\nDone."; sub rev { $len = length ($phr); $phr =~ s/\s+(w+)\s+(w+)/$2\s+$1; print "$phr\n"; } sub initargs { $phr; }


Now just so you know this script is in an extremely primitive state.

I usually like to get my scripts to a little highler level of sophistication before posting to the monks. Usually, what I do is start with making the script ridiculously simple and get elements to work one at a time before proceeding. So, there are stylistic and logic issues all over the place on this one. I think I know most of them already, but if you would still like to comment on those aspects, by all means! be my guest! that's what you get for putting your learning curve on the 'net. Sorry to merlyn, btw. I think I may have misinterpreted your blog (if you do read this). It was late, I was tired and gumpy. Oh well. My point being, that the trap door on my jammies is open and my ass is hanging out on this one! And I don't particularly care who's lookin' at my bum!

But I just learned about regexes and how to 'write them' -which I still can't claim to know how to do, as evinced by this post! - a couple of weeks ago, and my facility with them is still incredibly shaky!

This book, by the way has been calling and calling to me from my bookshelf for over 6 mos now! My original intention was to get through Lemay's Book - I really like her chatty, personal style, by the way - but then dive into MySQL in 21 Days and then proceed onto Mastering Regular Expressions before taking on merlyn's book or any other IT related projects.

The specific reason of the "quick learn" method I'm currently engaged in with the Sams 21 Days series is that my friend and I want to set up our little lemonade stand on the net and see who comes. If I don't learn it, he's going to find someone else! But I assure you that I fully intend on reading merlyn, wall and anyone else you'd care to suggest - eric s. raymond was also a particularly good suggestion that someone made!

But, as usual, I welcome any and all comments, so if you would like to offer any suggestions on my learning process I would like to encourage you to fire away!!!

THANKS TO THE MONKS!!!

Replies are listed 'Best First'.
Re: No grokkage on regex search/replace
by davido (Cardinal) on May 23, 2004 at 17:08 UTC
    First, your code shouldn't even compile; your s/// operator doesn't have a terminating '/' character. Be sure to paste actual code snippets wherever possible.

    Now for the analysis:

    One problem is that metacharacter-classes and quantifiers are meaningless on the right-side (the replacement side) of an s/// operator. You can't say, "s/\s+(\w+)/$1\s+/;"

    That should be written something more along the lines of:

    # Wrong: $phr =~ s/\s+(w+)\s+(w+)/$2\s+$1; $phr =~ s/\b(\w+)(\s+)(\w+)\b/$3$2$1/;

    Also, I really do think you're doing yourself a disservice by not picking up a copy of the Llama book, "Learning Perl." That is the introductory course of choice. It just seems like your code has a lot of non-perlish nuggets. For example, what is your initargs() subroutine supposed to be doing? And why is it passing variables around through osmosis instead of through proper parameter lists and return values?

    And don't forget:

    use warnings; use diagnostics;

    .... at least while learning.

    Update: One more thing... Please be careful to learn about security issues if you plan to place an online CGI script that deals with money, takes user input, etc. I really think that's too important to gloss over in your first 21 days of Perl programming. We've recently seen what happened to Nik, who ignored warnings about CGI security concerns. Putting a script where others will be executing it (such as CGI) is not something to be done carelessly.


    Dave

      Also, I really do think you're doing yourself a disservice by not picking up a copy of the Llama book, "Learning Perl." That is the introductory course of choice. It just seems like your code has a lot of non-perlish nuggets. For example, what is your initargs() subroutine supposed to be doing? And why is it passing variables around through osmosis instead of through proper parameter lists and return values?

      Thanks for the pointers! Very useful indeed! As to the points that I was "ignoring" from other quite useful posts...for some points and concepts (though I decline to go into specifics here, more in the interest of brevity than any sense of peevishness that I don't in fact harbor. and though you'd have no way of knowing this was merely because of the extremely early stages of this script) I was in fact purposefully doing so in the interests of getting a script off the ground when I was really shooting to get a tighter grip regexing. Whenever learning a new language, sometimes a blank vi terminal looms like a blank canvas for even the simplest tasks.

      I'm a not terrible (though certainly not museum quality...maybe in my old age...) artist some of the time. Picking up a piece of chalk or a paintbrush to a blank sheet of paper or taking a knife to a bit of clay is a minor act of courage. I'm sure that feeling doesn't go away once you've deveoped great facility with a language and you have an ambitious project. But for these "baby steps" I'm taking here publicly on the web even something minor as "reverse a phrase" is a head-scratcher.

      Thanks for the reminder about the "reverse" function, by the by. For some reason that one slipped my mind! But I was finally convinced of the sisyphean nature of my struggles when I tried to "use strict;" as everyone here had been screaming at the top of their lungs (advisedly so, it would seem! huh! go figure! trust the monks!) for me to do and I couldn't even assign a variable in such a way that it would compile! "Oh shit!": says I. Not allowing myself to say (perhaps more appropriately) "whoa is me" and ordered the llama book quicker than you could say get thee to a nunnery!" Even ordered it for same day delivery (as I very luckily work in the center of the whole damnable universe! ;) but sadly it failed to arrive in time for me to start absorbing (devouring? might actually be a better word?) during my hour+ train commute home. It'll be there tomorrow (godwilling) so I can start...again...from.........SCRATCH!!!!! AAAARRRRGH!!!!! DAMN YOU LAURA LEMAY!!! YOU WANTON TROLLOP!!!...you...IMPUDENT STRUMPET!!!...harumph...grumble...

      Seriously, though I bear no will of personal ill tidings towards the woman Laura Lemay herself, if Sams is still publishing that book they should stop. Immediately. It's about the same vintage as the Llama book. And if I'm more than half way through it and I have yet to see word one about the use of strict off to the dustbin it goes! I've always had the best of luck with O'Reilly. If I weren't already having my head examined, I'd say "I should have my head examined" for looking anywhere else! pheh!
Re: No grokkage on regex search/replace
by thor (Priest) on May 23, 2004 at 17:29 UTC
    Just so you know, even if you get this working, it will not conform to the spec. Basically, the path that you are going down is a subroutine that, when complete, will reverse a string of two words. For the more general solution, take a look at the built-in functions reverse and split. I think that they will help tremendously.

    thor

    p.s. welcome to the fold
Re: No grokkage on regex search/replace
by ambrus (Abbot) on May 23, 2004 at 19:46 UTC

    Semicolon after use strict!

    If you forget the semicolon after the use strict, in older perls (5.6 or 5.005) it will just do nothing silently, and strict does not come into effect. In newer perls, you are likely to get an error, but not always. That's because the next expression is taken as an argument of use strict. (Useing strict without a semicolon was a useful obfu technique seen in many older obfus. Those now don't work with newer perls.)

Re: No grokkage on regex search/replace
by Anonymous Monk on May 23, 2004 at 18:59 UTC
    You might try something like this.
    #!/usr/bin/perl use strict; use warnings; use diagnostics; PrintInRevWordOrder ("The tall brown cat walked down the alley-way."); sub PrintInRevWordOrder { my @string = split /\s+/, shift; # the problem says this is to be passed as an argument # but you are using global variable. bad practice in general. # C-stlye for loop ... usually I use more perl-esque structures, # but hey -- TMTOWTDI (there's more than one way to do it!) for (my $i = $#string; $i > 0; $i--) { print $string[$i], " "; } }
    (Oh, and my sentence brings up a useful discussion of what do you consider a word ... I doubt the problem specifies it exactly, but would you want 'alley-way' to be a single word, or would you want it to be reversed to way-alley or some other variant? It changes what approach you take--albeit a simple change in this case. Also, regexes aren't always the answer. They can be *extremely* powerful and useful ... but don't use a nuke to kill a fly when you've got a perfectly good flyswatter.) For information on the 'split' function you might try here. For info on using strict, I recommend searching around the monastary ... and if your book doesn't have it, well, ditch it! And as said before, be very wary of doing anything in CGI without first knowing a heck of a lot about security ... it doesn't hurt to emphasize it again, so make sure you research some on this. Again, this site is a good resource, but a decent cgi book would be another resource. But first things first,
    sub rev { $len = length ($phr); $phr =~ s/\s+(w+)\s+(w+)/$2\s+$1; print "$phr\n"; }
    WHy do you need the length? You don't use it anywhere else. And you seem to again be using global variable, despite previous comments about them. That leads me to believe you don't understand, rather than that you are ignoring the comments about them. Again, this site is a good resource, the web in general or a decent programming book. It gets into topics like "namespace" and object-oriented design principles such as encapsulation ... so if you've never heard of any of this before, search around or ask and you're likely to get an answer.
    sub initargs { $phr; }
    What? This is *not necessary*. In perl, you do not need to intialize your variable. It is, though, good practice to declare them. But, again, this is a global variable. At the start of your sub, you might say "my $phr" but this here does nothing useful whatsoever. Look up what 'my' does in your book. If it doesn't talk about it, further reason to get the Camel. It's starting to look like you'll just be spending more of your time re-learning bad practices if you don't get it soon ;)
      Oh, and I also came up with this as another method. It uses the 'reverse' function (search for it here if you can't figure it out).
      #!/usr/bin/perl use strict; use warnings; use diagnostics; PrintInRevWordOrder ("The tall brown cat walked down the alley-way."); sub PrintInRevWordOrder { my @string = split /\s+/, reverse shift; print reverse($_) . " " for @string; }
      And, quite embarisingly, I made the classic off by one mistake in my previous code. I *did* test it, ... but not closely enough, apparently! The first word never appears, because the for statement needs to read "<= 0" instead of "< 0" -- I guess that's what I get for going to C-like syntax, which I did since I figure you'd be more familiar with it. Pooh! :P

      It really would be better if you used for(my $i=$#string;$i >= 0; $i--) unless you're sure you don't want to print $string[0]

      --
      TTTATCGGTCGTTATATAGATGTTTGCA

Re: No grokkage on regex search/replace
by fluxion (Monk) on May 23, 2004 at 21:38 UTC
    By the way, curious, but which author is merlyn? Randall or Tom?

    Randall

    Roses are red, violets are blue. All my base, are belong to you.