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

Hi, I'm really new at Perl. I'm one day into the language to be exact. :) Already, I'm stuck. I'm trying to write a multipart program in Perl. The first part searches the user's input for a certain pattern (which the user specifies the pattern) and replace it with another pattern (which the user also specifies) and prints it out. I don't know Perl well enough to know what I'm doing wrong - which is probably everything. Here is what I have.
sub replace{ print "\nSearch Pattern: "; $pattern = <STDIN>; chomp($pattern); print "\nReplacement Pattern: "; $replacement = <STDIN>; chomp($replacement); while (<>){ if ($pattern){ substr($_, 0) = "$replacement"; } } }
Another thing I'm trying to do is make sure that if the pattern is capitalized in the search file (not the search pattern), my replacement pattern should also mirror it. I don't know if knowing this will change my programming or not. I hope that wasn't too confusing. Any help is much appreciated. (If you don't mind, please comment so I can learn.)

Replies are listed 'Best First'.
Re: Searching and Replacing
by wiz (Scribe) on Jul 04, 2001 at 00:43 UTC
    you should use s///

    like this

     s/$pattern/$replacement/;
    that would replace all instances of $pattern. but the rest looks good to me. (this replaces the While Input code)


     Update use s///g to replace all instances. Thanks runrig for the correction.
Re: Searching and Replacing
by tachyon (Chancellor) on Jul 04, 2001 at 01:18 UTC

    The first two parts are fine. You grab your search an replacement patterns and chomp of the newlines (you don't need the parens with chomp BTW).

    Next it gets a bit confused. The <> construct is essentially the same as <STDIN> (see ChemBoy's post below). Within the while loop each input from STDIN is aliased to the magical $_ perl special variable. Here is some working code:

    print "\nSearch Pattern: "; chomp(my $pattern = <>); $pattern = uc quotemeta $pattern; print "\nReplacement Pattern: "; chomp(my $replacement = <>); print "\nInput: "; while (<>) { chomp; last unless $_; s/$pattern/$replacement/ig; print; print "\nInput: "; }

    The input sections are almost the same but I demonstrate a good use for parens with chomp to do in one line what was two before. I have also declared $pattern and $replacement as lexically scoped variables with my - this is a good idea otherwise all your variables will be globals. The $pattern = uc quotemeta $pattern does two things. The uc() function converts $pattern to UPPER CASE as desired and the quotemeta() escapes (with a \) all the meta charcters that can break your regex because the take on a non literal meaning in a regex.

    We then demand some input from STDIN in an infinite while loop. As I noted this is assigned to the magical $_ var. This var is the default target of many perl functions. You see that I do a chomp, substitution and print without specifying what to do them on! They all target $_ - you either love this behaviour or hate it. I have added a last unless $_ so if we enter a null string we break out of this infinite loop. In perl 0, undefined and the null string '' are all false - everything else is true. With the substitution regex the /ig at the end are modifiers. the /i means ignore case (which we need to as we uppercased our $pattern) and the /g stands for global as in replace all occurences.

    Hope this helps. Have fun and welcome.

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n\w+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      A minor but (IMO) important quibble: <STDIN> and <> are not identical constructs. If you use the script without command-line arguments, they are, but if a file is specified in @ARGV, reading from the magic filehandle (<>) will read from that file, while reading from STDIN (<STDIN>) will read from the standard input, aka the terminal.

      Example code:

      #!/usr/bin/perl use strict; my $color; print "What is your favorite color? "; chomp ($color = <STDIN>); print <>; print "Just to check, your favorite color is $color, right? "; $_ = <STDIN>; if ( /^y/i ) { print "Phew!\n" } else { print "I don't believe you!\n"}

      If run thus

      perl myscript.pl random_file.txt
      this should give us

      What is your favorite color? Blue
      [ contents of random_file.txt ]
      Just to check, your favorite color is Blue, right?Yes!
      Phew!

      This is occasionally very useful behavior--I wouldn't be at all surprised if it was pretty much what you need, Satira.

      And of course, in real quibble land, tachyon didn't mean an infinite loop, he meant a loop until the filehandle reaches EOF. :-) If you're looping on <>, this will take care of itself unless you do something foolish; if you're looping on STDIN, you can break out by giving the locally appropriate EOF character (control-D on most Unices and MacPerl, control-Z on Windows I think...).



      If God had meant us to fly, he would *never* have give us the railroads.
          --Michael Flanders

        Thanks for that ChemBoy - I was unaware of the <> and @ARGV behaviour. File another pearl. Sure it's not technically an infinite loop as you point out but having a way to break out of it is a good idea. Much better than control ?D ?Z ?X ?C or even the ever faithful Ctl-Alt-Del ;-)

        print "Your call is important to us please hold...\n"; for (;;) { while (1) { print "I committed a technical inexactitude\n" until 0; } } print "Did you wait long!\n";

        tachyon

        s&&rsenoyhcatreve&&&s&n\w+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Searching and Replacing
by runrig (Abbot) on Jul 04, 2001 at 00:53 UTC
Re: Searching and Replacing
by jeroenes (Priest) on Jul 04, 2001 at 10:07 UTC
Re: Searching and Replacing
by Satira (Novice) on Jul 04, 2001 at 12:45 UTC
    Hi again, since I didn't know how to edit my top post and didn't want to start a new thread, I will update here. Well part of my program works. The replacement string works but it doesn't preserve the capitalizations from the original text. For example: This is what it currently does:
    User Input: She sells Seashells by the seashore. Search Pattern: sea Replacement Pattern: bay Final Output: She sells bayshells by the bayshore. But what I want it to do is keep the capitalization. Final Output: She sells Bayshells by the bayshore.
    I don't really know where to begin on this. All I know is that I am not suppose to use arrays or hashes and I'm suppose to convert all the User Input into a lower case copy and work from there. I know some of the functions I am allowed to use are index, substr, length, rindex, lc, lcfirst. Since I can't really expect answers without trying, here's the algorithim I thought up but don't know how to implement. Let's say User input is stored in $input Then I make a lower case copy of $input and call it $lcinput When the user enters the search pattern $pattern and we make it also all lower case. So the program searches for $pattern in $lcinput, when it finds it, index should get the position of the pattern in $lcinput and compare it to that position on $input. If the strings are equal then it just inserts the replacement pattern $replace into both positions in $lcinput and $input to keep the string lengths the same. If the string compare returns that at a certain position the words are unequal then we know there's a capitalization in $input and we modify $replacement to be capitalize. After it goes through the whole length of $lcinput, then we know that we've indirectly gone through $input also. Thus we are done and we print $input and that should be the correct output. I'm sure there is some faulty thinking in there somewhere. But if anyone can point me towards a direction or where to look so i can reference without hashes, arrays, slices, list, and so forth let me know. Here's what I have:
    main(); sub main { print "Text to be analyzed.\n"; print "Type a blank line when finished.\n\n"; while (<>) { /^$/&& last; $input.=$_} chomp($input); replace (); $input = ""; again (); } sub replace { print "\nSearched for: "; $pattern = <>; chomp($pattern); print "\nReplace with: "; $replacement = <>; chomp($replacement); $input =~ s/$pattern/$replacement/ig; }