| af Niels Hallenberg | sidst rettet 8. oktober, 2001 |
At et cpr-nummer opfylder modulus 11 kravet betyder ikke nødvendigvis at der findes en person med dette nummer. Dog vil alle cpr-numre opfylde modulus 11 kravet, så det er en god test der sikrer mod taste fejl.
Du skal lave en fil cpr.html som indeholder et
inddatafelt hvor brugeren kan indtaste et cpr-nummer, samt en
"submit"-knap der kalder Tcl programmet cpr.tcl:
I Tcl programmet cpr.tcl laver du et regulært udtryk som
ved hjælp af kommandoen regexp binder de 10 tal i
cpr-nummeret til variable c1,...,c10;
dvs. hvert tal i cpr-nummeret bindes til hver sin variabel.
Eksempel: Med cpr-nummer 291270-1234 bindes c1 til 2,
c2 til 9, c3 til 1, ..., c10
til 4.
Hvis det indtastede cpr-nummer ikke opfylder dit regulære udtryk, så returnerer du en passende fejlmeddelelse.
Du skal lave en procedure chk_modulus11, som tager de 10
tal som argument og udfører et modulus 11 check på de 10 tal:
proc chk_modulus11 {c1 c2 c3 c4 c5 c6 c7 c8 c9 c10} {
set sum [expr ...]
if {[expr ...] == 0} {
return 1
} else {
return 0
}
}
For at udføre et modulus 11 check sætter du variablen sum lig følgende beregning:
hvorc1*4 + c2*3 + c3*2 + c4*7 + c5*6 + c6*5 + c7*4 + c8*3 + c9*2 + c10*1
c1, ..., c10 er de ti tal i
cpr-nummeret. Hvis indholdet af variablen sum modulus 11
giver 0, så er modulus 11 checket opfyldt, dvs. du skal udføre
beregningen sum % 11 og se om resultatet giver 0.Følgende billeder viser et cpr-nummer som opfylder modulus 11 kontrollen og et cpr-nummer som ikke opfylder modulus 11 kontrollen:
Bemærk, at modulus 11 kontrollen ikke checker om fødselsdatoen er
valid, så derfor kan du forbedre servicen ved også at kontrolere, at
fødselsdatoen er en korrekt dato. Du kan f.eks. anvende procedureren
date_ok fra weekday.tcl på lb5-ekstra.html til at kontrollere at
datoen findes.
| Vægt i gram | Takst i kr. |
|---|---|
| mindre end 0 | Brev kan ikke sendes |
| op til 20 | 4,00 |
| op til 50 | 5,25 |
| op til 100 | 5,75 |
| op til 250 | 9,75 |
| op til 500 | 17,00 |
| op til 1000 | 21,00 |
| op til 1500 | 28,00 |
| op til 2000 | 30,00 |
| mere end 2000 | Brev kan ikke sendes |
Brugeren vælger vægten fra en valgliste (select). Når
brugeren har valgt en vægt klikker brugeren på knappen mæket
Beregn, hvorefter Tcl programmet returnererer en HTML side med
portoen angivet. Den første figur nedenfor viser portoberegneren
første gang brugeren ser den, og det andet billede viser den HTML side
brugeren får retur. Læg mærke til, at brugeren kan vælge en ny vægt i
den HTML side der også indeholder portoen på det sidste valg.
Det er en fordel at registrere vægte og portoer i Tcl programmet som en liste af lister:
set vaegte [list [list "mindre end 0" "kan ikke sendes"] [
list "op til 20" "kræver 4.00 i porto"] [...
Ideen er, at hver vaegt/porto par består af to tekster: vægt og
porto. Parret med vægt og porto for 'mindre end 0' har indeks 0 i
listen vaegte og parret for 'op til 20' har indeks 1 i
listen. Koden for valglisten i formen, kan f.eks. se således ud:
Hvis brugeren vælger 'mindre end 0 gram', så registreres indeks 0 i form-variablen<select name=vaegt> <option value="0">mindre end 0 gram <option value="1">op til 20 gram ... </select>
vaegt, og hvis 'op til 20 gram' vælges
registreres indeks 1 i form-variablen vaegt. På den måde
kan vi i Tcl programmet finde frem til både vaegt og porto på det brev
som brugeren skal sende.
Hvis variablen vaegt indeholder indekset på det brev
brugeren har valgt (enten 0 eller 1 i eksemplet ovenfor), så kan vi i
Tcl programmet få
set vaegt [lindex [lindex $vaegte $vaegt] 0]
set porto [lindex [lindex $vaegte $vaegt] 1]
Opgaven består kun af en fil porto.tcl, som undersøger om
form-variablen vaegt er tilstede. Hvis form-variablen
ikke er tilstede, så returneres en tom portoberegner til brugeren
(første billede ovenfor); ellers returneres portoen på det valgte brev
samt en ny form (andet billede ovenfor).
Du kan bygge dit program omkring følgende skabelon:
set_form_variables 0
proc home_page { title body } { ... }
proc my_return_page { title body } {
ns_return 200 text/html [home_page $title $body]
}
set vaegte [list [list "mindre end 0" "kan ikke sendes"] [
list "op til 20" "kræver 4.00 i porto"] [...
proc mk_vaegt_liste {vaegte} {
# Returner en valgliste (select)
}
proc porto_form {vaegte} {
set page "<h2>Portoberegner</h2>
<form method=post action=porto.tcl>
...
</form>"
}
if {![info exists vaegt]} {
# Returner en HTML side, hvor bruger kan vælge en vægt.
} else {
# Find porto givet vaegt.
# Find teksten på vaegt
# Returner en HTML side med angivelse af tekst på vægt og porto,
# samt en ny form, hvor bruger kan vælge en ny vægt.
}
Ekstra: Udvid med at anvende et regulært udtryk til at checke,
at form-variablen vaegt indeholder et heltal.
| Vægt i gram | Takst i kr. |
|---|---|
| mindre end 0 | Brev kan ikke sendes |
| op til 20 | 3,75 |
| op til 50 | 5,00 |
| op til 100 | 5,50 |
| op til 250 | 9,25 |
| op til 500 | 16,00 |
| op til 1000 | 20,00 |
| op til 1500 | 27,00 |
| op til 2000 | 29,00 |
| mere end 2000 | Brev kan ikke sendes |
En måde at udvide programmet på er at udvide listen
vaegte, således at der til hver vægt findes to portoer,
en for almindelig forsendelse og en for økonomibreve:
set vaegte [list [list "mindre end 0" "kan ikke sendes" "kan ikke sendes"] [
list "op til 20" "kræver 4.00 i porto" "kræver 3.75 i porto som økonomibrev"] [
...]]
Når portoen beregnes henter du portoen fra indeks 1 hvis checkboksen
ikke er valgt og portoen fra indeks 2 hvis checkboksen er valgt.
Opgaven synes måske noget svær, men hvis du går systematisk frem, og gennemtænker opbygningen af programmet inden du koder, så er det ikke så svært. Den vejledende løsning er på 61 linier. alt inklusive.
Brugeren præsenteres en form der indeholder
Formen indeholder følgende form-variable:
sum, som er skjult og angiver summen af de samlede
registrerede indkøb. Variablen er nødvendig for løbende at kunne
beregne den samlede sum.
strimmel, som er skjult og angiver den kassestrimmel
som brugeren ser. Variablen er nødvendig for løbende at kunne udvide
kassestrimlen.
vare, som angiver brugerens valg fra valglisten af
varer. Det er en fordel at registrere varesortimentet i Tcl programmet
som en liste af lister:
set varer [list [list "1½ Coca Cola" 16.50] [
list "1½ kg. kartofter" 10.25] ... ]
Ideen er, at hver vare består af en tekst og en pris. En cola har
indeks 0 i listen varer og et 1½ kg. kartofler har indeks
1 i listen. Koden for valglisten i formen, kan f.eks. se således ud:
Hvis brugeren vælger en cola, så registreres indekset på colaen (indeks 0) i form-variablen<select name=vare> <option value="0">1½ Coca Cola(16.50) <option value="1">1½ kg. kartofter(10.25) </select>
vare, og hvis kartoflerne
vælges registreres indeks 1 i form-variablen vare. På den
måde kan vi i Tcl programmet finde frem til både tekst og pris på den
vare som brugeren har valgt.Hvis variablen indeholder indekset på den vare brugeren har valgt (enten 0 eller 1 i eksemplet ovenfor), så kan vi i Tcl programmet få
set varenavn [lindex [lindex $varer $vare] 0]
set pris [lindex [lindex $varer $vare] 1]
antal som indeholder det antal styk brugeren ønsker
af den pågældende vare.
kassestrimmel.tcl, som
undersøger om de fire form-variable er tilstede. Hvis form-variablene
ikke er tilstede, så returneres en tom kassestrimmel til brugeren:
Hvis form-variablene er tilstede, så opdateres kassestrimlen og den løbende sum, hvorefter den opdaterede kassestrimmel returneres til brugeren, således at brugeren kan gøre flere køb. Figuren viser ændringen fra det første billede ovenfor, og efter at brugeren har valgt to liter saftevand.
Du kan bygge dit program omkring følgende skabelon:
set_form_variables 0
proc home_page { title body } {...}
proc my_return_page { title body } {
ns_return 200 text/html [home_page $title $body]
}
set varer [list [list "1½ Coca Cola" 16.50] [list "1½ kg. kartofter" 10.25] ...]
proc mk_vare_liste {varer} {
# Her kan du bygge valglisten, dvs. HTML kode (select)
# som skal indsættes i den form brugeren ser.
}
# strimmel_form genererer HTML kode for den form brugeren
# ser. Procedureren kaldes både, når strimlen er tom, og når den ikke er
# tom.
proc strimmel_form {varer sum strimmel} {
# variabel varer indeholder listen af varer
# variabel sum indeholder den løbende sum, som skal skal udskrives i
# formen og som er skjult i formen.
# variabel strimmel indeholder strimlen, som skal udskrives i
# formen, og som er skjult i formen.
set page "<h2>Kassestrimmel</h2>
<form method=post action=kassestrimmel.tcl>
...
</form>"
}
if {![info exists sum] ||
... } {
# Her returnerer du en tom kassestrimmel ved bl.a. at kalde
# procedureren strimmel_form med varesortimentet, sum lig 0 og
# strimmel lig den tomme streng.
} else {
# Beregn pris på den valgte vare
# Beregn varenavn på den valgte vare
# Udvid strimmel med det nye køb
# Beregn ny løbende sum
# Returerer en opdateret kassestrimmel ved bl.a. at kalde
# procedureren strimmel_form med varesortimentet,
# den opdaterede sum og den opdaterede strimmel.
}
Ekstra: Udvid med at anvende regulære udtryk til at checke, at
form-variablene indeholder værdier der syntaktisk svarer til det
forvende.