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

for Database-baseret Web-publicering, forår 2001

af Niels Hallenberg sidst rettet 05. marts, 2001


I sidste uge var der en del problemer med at logge på IT-C's maskiner i øvelokalerne. Jeg har i d.d. checket, at jeg på alle maskiner i 3.15 og 3.16 kunne (1) logge på IT-C's netværk og (2) logge på hug.itu.dk med ssh. Jeg håber hermed, at vi ikke får flere problemer med dette.

Hvis du har problemer med at logge på hug, så check først, at du anvender programmet SshClient, som er installeret i kataloget:

Program Files\SSH Communications Security\SSH Secure Shell\

Det skulle meget gerne være det program, som du starter, når du vælger SshClient i menuen. Du checker det f.eks. ved at åbne folderen C: på computeren, og derefter klikke dig ned til kataloget hvor SshClient ligger og derefter starte SshClient.

Med hensyn til løbeseddel 4, så er afleveringsfristen udskudt til fredag den 9. marts klokken 09.00. Dette vil nok også rykke datoen for hvornår I får de rettede opgaver retur. Udskydelsen gør, at I får lejlighed til at arbejde med opgaverne fra løbeseddel 4 på hug, mens I har øvelser.

I denne løbeseddel øver vi kommandoen string compare samt regulære udtryk, som er gennemgået til forelæsningen tirsdag d. 6. marts.

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 en web-site i Sverige og anvender kursen til bl.a. at vise, hvor mange danske kr. man kan købe for 100 dollars.

Der er lavet en lille ekstra opgave i denne uge, som anvender regulære udtryk. Til opgaven 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 (45 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, inklusive æ, ø, å, Æ, Ø og Å. (5%).

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

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

  2. strenge startende med et bogstav, efterfulgt af 0 eller flere bogstaver eller talcifre (5%). Du skal inkludere de danske bogstaver æ,ø,å,Æ,Ø og Å.

    Følgende strenge skal genkendes: "a", "dkdjs324", "akd", "a348384akldfaslkf" og "æøåÆØÅ1".

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

  3. strenge startende med et bogstav, efterfulgt af 0 eller flere bogstaver, talcifre eller underscores (5%). Du skal inkludere de danske bogstaver æ,ø,å,Æ,Ø og Å.

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

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

  4. reelle tal (5%). Vi definerer et reelt tal til en streng der opfylder mindst et af nedenstående:

    Vink:Dit mønster skal tage højde for to muligheder: (1) tvungen tal til venstre for . og mulighed for tal til højre. (2) tvungen tal til højre for . og mulighed for tal til venstre. Du angiver valgmuligheder med |. Et tvungen tal kan f.eks. laves med [0-9]+. Et valgfrit tal kan f.eks. laves med [0-9]*. Punktum er altid valgfri, dvs. du kan anvende \.? til at matche punktum.

    Følgende strenge skal genkendes: "1", "1.", "1.0", ".1", "1032.343", ".04330" og ".3".

    Følgende strenge skal ikke genkendes: "1a2", ".", "32,23", "a.3" og "to.3".

  5. email (5%). 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".

  6. navn (5%). Et navn er en vilkårlig ikke tom sekvens af tegn bestående af bogstaver fra det danske alfabet, cifre, mellemrum og tegnene: ' og -.

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

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

  7. 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".

  8. url, defineret ved sekvensen af tegn startende med http:// efterfulgt af en ikke tom sekvens af tegn fra det engelske alfabet, cifre, ., / og _.

    Følgende strenge skal genkendes: "http://a", "http://4_a" og "http://a/aa.html".

    Følgende strenge skal ikke genkendes: "", "http://", "http://a€#" og "http://aø.tcl".

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

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

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 (40 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

nh@it.edu