Løbeseddel 5: Streng-matching og indhentning af data fra fremmede web-sites

for Databasestøttet Webpublicering

af Martin Elsman og Niels Hallenberg sidst rettet 08. marts, 2002


I denne løbeseddel øver vi kommandoen string compare, lister, samt regulære udtryk.

Opgave A går ud på at lave to procedurer, som letter sammenligning af strenge. Ideen er, at vi anvender procedurerne hver gang vi har brug for at teste (1) om en streng er tom eller (2) om to strenge er ens.

Opgave B i denne øvelse træner mønstre og regulære udtryk med regexp-kommandoen.

I opgave C laver vi en service, som henter dollarkursen fra et web-site i Sverige og anvender kursen til bl.a. at vise, hvor mange danske kr. man kan købe for US$ 100.

I opgave D træner vi anvendelsen af lister.

Der er lavet en lille ekstra opgave i denne uge, som øver regulære udtryk. Til den ene opgave (ugedag) følger en del kode, som man skal anvende for at løse opgaven. Dette har bl.a. til hensigt at øve brugen af andres kode. Det er vigtigt for en programmør, at man er i stand til at sætte sig ind i andres kode, således at man kan arbejde sammen på større projekter.

Opgave A (15 procent) - Sammenligning af strenge

Til forelæsningerne har vi set, at kommandoen
string compare $str1 $str2

er lidt irriterende idet den returnerer 0 (som også er værdien for falsk) hvis de to strenge $str1 og $str2 er ens og henholdsvis 1 og -1 hvis de er forskellige. Vi har tit brug for, blot at vide om de to strenge er ens eller ej.

Du skal lave en procedure equal_string som tager to argumenter (de to strenge), sammenligner dem og returnerer 1 hvis de er ens og 0 hvis de er forskellige. Du skal benytte kommandoen string compare. Nedenfor ser du en skabelon for procedureren.

proc equal_string { str1 str2 } {
  if { [string compare ... ...] == 0 } {
    return ...
  } else {
    return ...
  }
}

Du skal gerne kunne reproducere nedenstående:

% equal_string "Cool" "Cool"
1
% equal_string "bla" "blabla"
0

Vi har også tit brug for at se, om en streng er tom. Lav en procedure empty_string, som tager et argument str og returnerer 1 hvis $str er lig den tomme streng ("") og 0 ellers. Du kan med fordel anvende equal_string i implementationen af empty_string:

proc empty_string { str } {
  return [             ...              ]
}

Du skal gerne kunne reproducere nedenstående:

% empty_string "bla"
0
% empty_string ""
1

Løsningerne gemmes i filen /web/login/www/oevelse5/string_utils.tclhug.it.edu.

Opgave B (35 procent) - Mønstre

I denne opgave skal du opskrive forskellige mønstre til brug ved simpel pattern-matching med regexp-kommandoen.

Følgende mønster genkender f.eks. alle strenge bestående af nul, et eller flere tegn der enten er et a eller b eller en kombination af begge:

^[ab]*$
Læg mærke til, at jeg starter med ^ og slutter med $ således at jeg sikrer mig, at mønstret skal matche hele strengen for at strengen er genkendt. Du skal også anvende ^ og $ i dine besvarelser.

Du kan checke dine mønstre med regexp-kommandoen, f.eks.:

% regexp {^[ab]*$} ""
1
% regexp {^[ab]*$} "abba"
1
% regexp {^[ab]*$} "abbac"
0
hvor jeg i den sidste streng abbac har et c, som gør at strengen ikke genkendes af mønstret.

Angiv mønstre for

  1. strenge bestående af et eller flere bogstaver.

    Følgende strenge skal genkendes: "a", "aa", "askdkdj" og "as".

    Følgende strenge skal ikke genkendes: ";", "", "asdlkfj@&/" og "232".

  2. strenge startende med et bogstav, efterfulgt af 0 eller flere bogstaver eller talcifre.

    Følgende strenge skal genkendes: "a", "dkdjs324", "akd" og "a348384akldfaslkf".

    Følgende strenge skal ikke genkendes: "1", "", ";:dkjd" og "3a".

  3. strenge startende med et bogstav, efterfulgt af 0 eller flere bogstaver, talcifre eller underscores.

    Følgende strenge skal genkendes: "a", "dkdjs324", "akd", "a348_384a", "asdf_" og "a_".

    Følgende strenge skal ikke genkendes: "1", "", ";:dkjd", "_" og "_a".

  4. navne. Et navn er en vilkårlig ikke tom sekvens af tegn bestående af bogstaver, cifre, mellemrum og tegnene: ' og -.

    Følgende strenge skal genkendes: "Hans", "Pia Petersen", "Mc'laren", "Annette Pihl-Hansen" og "42".

    Følgende strenge skal ikke genkendes: "" og "Hans P€etersen".

  5. positive heltal, dvs. ikke tomme sekvenser af cifre der (1) er et enkelt ciffer 0 eller (2) et ciffer fra 1 til 9 efterfulgt af nul, en eller flere cifre fra 0 til 9.

    Følgende strenge skal genkendes: "0", "1", "42" og "100".

    Følgende strenge skal ikke genkendes: "", "a", "01" og "43d".

  6. emails. Vi definerer en email til: navn@firma.land, hvor

    Bemærk, at definitionen for en email anvendt her adskiller sig fra definitionen anvendt til forelæsning 6.

    Følgende strenge skal genkendes: "n@b.com", "nd#€#@bi.££.ddk", "big.name@big.com.edu", "name@it-c.dk" og "name@it.edu".

    Følgende strenge skal ikke genkendes: "n", "n@big", "n@big@bon.edu", "n@big.com@" og "to@3".

  7. sand og falsk, defineret ved true, false, t og f.

    Følgende strenge skal ikke genkendes: "", "True", "False", "T" og "F".

Alle delopgaver ovenfor tæller med 5 point hver.

Det anbefales at regexp-kommandoen bruges til at teste mønstrene. Løsningerne gemmes i filen /web/login/www/oevelse5/patterns.tclhug.it.edu.

Opgave C (35 procent) - Dollarkursen

Opgaven går ud på at konstruere en service som indhenter dollarkursen fra et andet web-site og benytter dollarkursen til at beregne antallet af kroner man kan købe for $100 og antallet af dollars man kan købe for kr. 100.

Servicen skal gøre brug af kommandoen ns_httpget, som kan bruges til at hente en HTML-side ind i en tcl-variabel som en streng (en sekvens af tegn).

Dollarkursen kan passende hentes fra Yahoo i Sverige. Følgende URL-adresse giver den nødvendige information i form af en HTML-side med dollarkursen sat i forhold til danske kroner:

http://se.finance.yahoo.com/m5?a=1&s=USD&t=DKK

Her er et udpluk af HTML-koden som ved opgavens konstruktion blev returneret ved ovenstående forespørgsel:

<table border=1 cellpadding=2 cellspacing=0>
  <tr bgcolor="#dcdcdc">
    <th>Kod</th>
    <th>Amerikanska dollar</th>
    <th colspan=2>Växelkurs</th>
    <th>Danska kronor</th>
  </tr>
  <tr align=center>
    <td><a href="/q?s=USDDKK=X&d=t">USDDKK=X</a></td>
    <td>1</td>
    <td>21:31</td>
    <td>7.977000</td>
    <td><b>7.98</b></td>
  </tr>
</table>
Vi er interesseret i tallet 7.977000 i HTML-koden, hvilket betyder, at vi giver 7.977000 kr. for $1. Her er et passende mønster, som kan bruges til at matche HTML-koden og binde det ønskede tal til en tcl-variabel ved brug af regexp-kommandoen:

set pattern {USDDKK.+<td>([0-9]+).([0-9]+)</td>} 
Din opgave er at udfylde nedenstående skabelon og gemme resultatet i filen /web/login/www/oevelse5/dollarkurs.tclhug.it.edu:

# Return the current date in a nice danish format
proc getdate {} {
  clock format [clock seconds] -format "%d.%m.%Y"
}

# The usual procedure used to return an HTML page
proc home_page { title body } { ... }

proc my_return_page {body} {
  ns_return 200 text/html [home_page "Dollarkursservice" "
  <h2>Dollarkursservice</h2><b>for [getdate]</b><p>
  $body"]
}

# Get the HTML page that contains the dollarrate  
set valuta_html [ns_httpget "http://se.finance.yahoo.com/m5?a=1&s=USD&t=DKK"]

# The pattern to use with the regexp command
set pattern {USDDKK.+<td>([0-9]+).([0-9]+)</td>}

if { [regexp ... dollarkurs1 dollarkurs2] } {
  # there is a match
  set dollarkurs "$dollarkurs1.$dollarkurs2"
  my_return_page "For \$100.00 får du kr. ... <p>
               For kr. 100.00 får du \$ ..." 
} else {
  # no match; something went wrong!
  my_return_page "Servicen er ikke tilgængelig! <p> 
    Send mig venligst <a href=\"mailto:login@itu.dk\">email</a>."
}
Indsæt et link til servicen fra din index.html side på hug.it.edu.

Vejledende løsning:

dollarkurs

Opgave D (15 procent) - Dagens Kage

I denne opgave er der givet en liste med kageopskrifter (opskrifter). Hver kageopskrift er i sig selv en liste der indeholder Derudover er vi givet en liste (aarstider) der beskriver nogle dage i løbet af året, f.eks. "en fantastisk forårsdag".

Det er nu din opgave, at lave en service Dagens Kage, som returnerer en HTML side med en tilfældig valgt opskrift. Din løsning skal inkludere en tilfældig valgt dag fra listen aarstider. HTML siden skal have et indhold svarende til den vejledende løsning. Klik "reload" for at få en ny opskrift (til en ny dag).

Din service skal være tilgændelig på hug.it.edu i filen /web/login/www/oevelse5/dagenskage.tcl.

Du kan med fordel anvende procedureren udtag_fra_liste som blev gennemgået til forelæsning 5. Du kan anvende følgende skabelon (de første 66 linier opretter listen med opskrifter, så der er ikke så mange reelle kodelinier).


mael@it.edu, nh@it.edu