Previous | Home | Lecture Notes | Exercises | Next

 

Perl Solutions (4)


These exercise solutions are part of a Perl course taught at CNTS - Computational Linguistics at the University of Antwerp.

The programs corresponding with these exercises can be found in the appendix.

Exercise 4.1

Write a program that reads one line with integer numbers and prints the square of all the even numbers greater than 10.

To do this, we must read a line and split it into numbers. A foreach loop then considers each number. Because we do not chop whitespace off the line, the array will also contain empty strings sometimes. We do not, however, need to filter these, and at the same time non-integer numbers, because we do a test to check whether the number conforms to the requirements of being even and larger than ten, and print its square (and non integers will fail anyway).

Exercise 4.2

Write a program that reads lines from standard input until end-of-file, then prints the number of lines, words and characters in the input, followed by the input in reverse order (both lines and characters).

To do this we must store all lines in a stack buffer and output them in the reversed order. We must also reverse the characters on each line. This, and the counting of characters, is done by splitting the line string on the empty regular expression, which gives a list of characters. By splitting the line on whitespace (NB: /\s+/) we get a list of words, that are also counted. The counting part of the program emulates the UNIX command "wc", short of the fact that chomp removes the newlines, so these are ignored in the count.

Exercise 4.3

Write a program that recognizes palindromes (words or phrases that read the same in both directions). Deal with one-letter words, and be permissive with whitespace and punctuation, so that the program behaves as specified by the example in the specification.

We want the program to write a prompt, ask for input and process the input until an empty line is given. For this we use a do{ ... }while(); construction. The recognition of the palindromes itself is easy: we split the line into letters, and compare the original with the reverse. But first we need to do some cleaning to deal with whitespace, punctuation, and lowercase conversion. Note that the function lc($string) is better than tr/A-Z/a-z/ as the former also deals with accented characters, but the latter does not.

Exercise 4.4*

Write a program that reads text from standard input until end-of-file, and then prints the frequency of each bigram that occurs in the text. And this without hashes.

See the solution below. There's surely a billion other ways to do this, some more and some less elegant. This solution is not the most elegant, but pretty straightforward and easy to translate into hashes later on. As the exact constraints are not specified by the exercise, we just try to give something "in the spirit of...". My solution tries to respect word boundaries. This is something you typically want to solve with hashes (direct access to the right item instead of the linear search on an array done here), but this will come back in next week's exercises.

Appendix

Exercise 4.1

#!/usr/local/bin/perl -w
# exercise4.1.pl: a program that reads one line with integer 
#                 numbers and prints the square of all the even 
#                 numbers greater than 10perform rot13 on a text
# 2000-03-03 zavrel@uia.ua.ac.be

print "Give a line of integer numbers separated by whitespace:\n";

$line = <>;

print "Output:";

@numbers = split /\s+/, $line;

foreach $num ( @numbers ){

    # test the properties of the number
    if($num % 2 == 0 && $num > 10 ){
	$square = $num*$num;
	print " $square"; 
    } 
 
}
print "\n";

Exercise 4.2

# exercise4.2.pl: a program that reads lines from standard input until
#                 end-of-file, then prints the number of lines, words 
#                 and characters in the input, followed by the input 
#                 in reverse order (both lines and characters).
# usage:      exercise4.2.pl
# 2000-03-03 zavrel@uia.ua.ac.be

# intitialize a line buffer
@lines = ();

# read lines of input
while(defined($line = <>)){
    
    chomp $line;        # this means that newlines will not be counted
    $nlines++;          # counts the lines
    @words = split /\s+/, $line;
    $nwords += @words;  # counts the words
    @chars = split //,$line;
    $nchars += @chars;  # counts the characters

    # reverse the characters in the line
    # and push this onto a stack
    @chars = reverse @chars; 
    $string = join "", @chars;
    push @lines, $string;
}
print "lines: $nlines, words: $nwords, characters $nchars\n";
print "reversed:\n";

# by popping lines off the stack they come out in the 
# reverse order:
while($line = pop @lines){
    print "$line\n";
}

Exercise 4.3

# exercise4.3.pl: a program that recognizes palindromes (words or 
#                 phrases that read the same in both directions). 
#                 Deals with one-letter words, and is permissive 
#                 with whitespace and punctuation.
# 2000-03-03 zavrel@uia.ua.ac.be

do{

    # read the input
    print "Type a word or phrase: ";
    $line = <>;
    
    # strip out stuff that would disturb the palindrome comparison
    # and convert to lowercase...
    $line =~ s/\W//g; # removes space and nonalphanumerics        
    $line =~ tr/A-Z/a-z/;  # converts to lowercase. Better: lc($line) !

    # get the list of letter and reverse it
    @letters = split //, $line;
    $reverse = join "", reverse @letters;
    
    # a palindrome is equal to its reverse or a one letter word.
    if(@letters == 0){
	print "End of session\n";
    }
    elsif(@letters == 1){
	print "One letter palindrome, trivial!\n";
    }
    elsif($reverse eq $line){
	print "This is a palindrome.\n";
    }
    else{
	print "Not a palindrome.\n";
    }
}while($line);

Exercise 4.4*

# exercise4.4.pl: a program that reads text from standard input until
#                 end-of-file, and then prints the frequency of each 
#                 bigram that occurs in the text. And this without hashes.
# 2000-03-03 zavrel@uia.ua.ac.be

@bigrams = ();

print "Please give me some input text:\n";
# read text until end-of-file
while(defined($line = <>)){

    # clean the line a bit (like chomp but both sides and all 
    # of the whitespace)
    $line =~ s/^\s*//;
    $line =~ s/\s*$//;
    
    # split into words to respect word boundaries
    # and ignore space-containing bigrams
    @words = split /\s+/, $line;

    # loop over the words...
    foreach $word ( @ words ){
	
	# split into letters
	@letters = split //, $word;
	
	# loop over the letters with a lookahead of one
	for($i=0 ; $i<$#letters ; $i++){

	   $bigram = $letters[$i] . $letters[$i+1];

	   # now store the bigram, this is kind of tedious 
	   # without hashes, but it just takes some extra search effort.
	   $found = -1;
	   if(@bigrams){
	      SEARCHBIGRAMINDEX: 
	      for($index = 0; $index <= $#bigrams; $index++){
	         if($bigrams[$index] eq $bigram){
		    $found = $index;
		    last SEARCHBIGRAMINDEX;
		 }
	      }
	   }
	   if($found > -1){
	      # adjust the frequency
	      $bigramfrequency[$found]++;
	   }
	   else{ # we haven't seen it before so we add it.
	      push @bigrams , $bigram;
	      $bigramfrequency[$#bigrams]++;
	   }
	}
    }
}

# now we have all the bigrams and their frequencies, so we print them
print "Bigram frequencies in your text:\n";
for($index = 0; $index < @bigrams; $index++){
    print "$bigrams[$index] $bigramfrequency[$index]\n";
}


Previous | Home | Lecture Notes | Exercises | Next
Last update: March 1st, 2000. zavrel@uia.ua.ac.be