Textverarbeitung mit Perl

Perl Praxis 6

In dieser Übung arbeiten wir weiter mit Hashes und lernen, wie man Subroutinen einsetzt, wie auch Module, um Daten aus dem Internet zu sammeln.


Man kann Subroutinen nicht nur im Körper eines Programms einsetzen, sondern auch innerhalb der Kontrollstruktur. Das folgende Programm ist eine Weiterführung des Programms wordcount.pl aus Perl Praxis 5. Der Unterschied ist, dass jetzt die Worte im Hash nach Häufigkeit sortiert ausgegeben werden.

Subroutinen
#!/usr/local/bin/perl
#erstellt Wortfrequenzen und gibt sie sortiert nach Frequenz aus

#wordcount-sort.pl FILE

while (<>) {
    chomp;
    tr/A-Z/a-z/;    #alles klein geschrieben
    tr/;:,.!-'"'?{}{}//d;   #Satzzeichen weg
    foreach $wd (split) {   #fuer jedes Wort
        $count{$wd}++;     #zaehle es.  key ist das Wort, 
	                   #value/wert ist wie oft es aufgetaucht ist
    }        
}         

foreach $w (sort by_number keys %count) { #fuer jedes Wort (key),sortiere
                              #wert/value=wie oft es das Wort im Text gab
    print "$count{$w} : $w\n";   #drucke die Häufigkeit
                              (wert/value) und das Wort 
}

sub by_number {  #subroutine, sortiert Zahlen
    $count{$b} <=> $count{$a}; 
}

Übung 6.1. Kopiere oder tippe das Programm in einen Editor und probiere es mit hexe.txt oder emerald.txt aus. In welcher Reihenfolge werden die Worte ausgegeben?
Übung 6.2. Wenn man die Worte in der umgekehrten Reihenfolge haben möchte, so muss man in der Subroutine nur die $a und $b Variablen vertauschen. Probiere das aus (die am wenigsten häufigsten Worte müssten jetzt zuerst angeführt werden).
Übung 6.3. Man kann jetzt die Worte noch alphabetisch sortieren in dem man die weitere Bedingung $a cmp $b mittels des "oder" Operators || eingibt. Probiere das aus.
Übung 6.4. Im Augenblick werden die Resultate des Programms wieder einfach nur am Terminal wiedergegeben. Ändere das Programmm, so dass die Resultate in eine Datei geschrieben werden.
Übung 6.5. Man kann die Anzahl der "keys", also wie gross die Hashtabelle eigentlich ist, mittles keys(%count) ermitteln. Wenn wir jetzt wissen möchten, wieviele Arten (type) von Worten auf die gesamte Anzahl von Worten kommt (type/token ratio), dann müssten wir das jetzt errechnen können (keys(%count) gibt "type", die Anzahl der einzelnen Worte kann man separat mittels einer Variable und dem ++ Operator errechnen). Errechne den type/token ratio für hexe.txt oder emerald.txt.


Bigrams

Man kann nicht nur das Vorkommnen einzelner Worte in einem Text auswerten, sondern man kann auch nachprüfen, welche Worte nacheinander erscheinen. Eine Kette von 2 Worten wird typischerweise ein "Bigram" genannt.

Übung 6.6. Statt einzelne Worte im count Hash unterzubringen, kann man auch eine Abfolge von 2 Worten dort lagern. Dies kann man so machen: wir setzen das erste Wort $x willkürlich auf \n oder auf ein Leerzeichen. Dann gehen wir in die foreach Schlaufe und finden unser erstes richtiges Wort, das nennen wir (z.B.) $y. Das Bigram von $x und $y können wir in einer weiteren Variable unterbringen: $z = "$x $y". Dies ersetzt nun $wd in dem Hash in der foreach Schlaufe. Ändere das Programm, so dass Bigrams ausgegeben werden (man muss auch noch das jetzige $y der $x Variable zuweisen, damit man beim nächsten Durchlauf der foreach Schlaufe schon gleich mal den richtigen Wert für $x hat). D.h., das Program sollte alle Bigrams ausgeben und wie oft diese im Text vorkamen.


Daten aus dem Internet

Das Program websearch.pl wurde von Michael Hammond erstellt und wird in seinem Buch beschrieben (S. 135-138). Es ist etwas komplex, da es auch von Subroutinen Gebrauch macht. Diese Subroutine müssen Sie nicht im Detail verstehen, Sie können Sie einfach benutzen.

Module
#!/usr/local/bin/perl
#sucht URLs nach einem bestimmten regulaerem Ausdruck durch
#websearch.pl 

#Ussage:  perl websearch.pl URL-NAME pattern number-of-hits

#Beispiel: perl websearch.pl http://spiegel.de euro 10
#Das durchsucht die Spiegel On-Line Webseite nach dem Muster "Euro"
#und hoert auf, sobald es 10 dieser Sorte gefunden hat. 

#This program searches the web for some pattern up to a maximum number of hits
#and prints out matching lines in the web pages it finds.
#
#Slightly revised for Berkeley workshop
#
#Mike Hammond, U. of Arizona, 2/2004

use LWP::Simple;

#checks command-line arguments
if ($#ARGV != 2) {
	die("usage: perl websearch.pl URL pattern hits\n");
}

#maximum number of links to hold in queue
$linkMax = 50;
#add seed link to queue
push(@urlstodo, $ARGV[0]);
#collect pattern
$pattern = $ARGV[1];
#collect maximum number of hits
$hitmax = $ARGV[2];

#loop until there are no more links or the maximum number of hits is reached.
while ($hits < $hitmax and $#urlstodo > -1) {
	$linksChecked++;
	#update the user on how many pages have been checked
	if ($linksChecked % 10 == 0) {
		print(STDERR "Checked: $linksChecked\n");
	}
	$theURL = pop(@urlstodo);
	push(@done, $theURL);
	#get the next page
	$mycontent = get($theURL);
	if ($mycontent) {
		@lines = split(/\n/, $mycontent);
		#go through the page line by line
		foreach $line (@lines) {
			#print out matching lines
			if ($line =~ /$pattern/) {
				print("$theURL:\t$line\n\n");
				$hits++;
			}
			#extract URLs and add them to queue
			if ($line =~ s/^.*(href|HREF)="([^"]+\.html?)".*$/\2/) {
				addURL($theURL, $line);
			}
		}
	}
}

#adds the url to the list of urls if it's not already there and hasn't already
#been checked.
sub addURL {
	my($url);
	#handle local links
	if ($#urlstodo < $linkMax) {
		my($prefix) = shift();
		my($suffix) = shift();
		if ($suffix !~ /^http/) {
			if ($prefix =~ /\/$/) {
				$suffix = $prefix . $suffix;
			} else {
				$suffix = $prefix . "/" . $suffix;
			}
		}
		#check if the URL has already been seen to avoid loops
		foreach $url (@done) {
			if ($suffix eq $url) {
				return();
			}
		}
		#check if the URL is already in the queue
		foreach $url (@urlstodo) {
			if ($suffix eq $url) {
				return();
			}
		}
		push(@urlstodo, $suffix);
	}
}


Übung 6.7. Experimentieren Sie mit dem Programm. Probieren Sie das Beispiel aus, dass ich im Programm angegeben habe, probieren Sie auch noch weitere Beispiele aus, mit anderen URLs.
Übung 6.8. Ändern Sie das Programm, so dass es alle gefundenen Zeilen in eine separate Datei schreibt.



Bitte die Übungen bis 9.7. an Anja Leiderer schicken!

Ende