Beispiel 5 - Zahlen in Strings konvertieren
Übersicht: Beispiel 5 - Zahlen in Strings konvertieren
Einleitung
Ziel dieses letzten Beispieles soll die Umwandlung einer Zahl in eine umgangssprachliche Zeichenkettendarstellung sein. Diese Aufgabe kann nur für endliche Zahlenbereiche gelöst werden, da für die verschiedenen Größenordnungen jeweils verschiedene (unberechenbare) Bezeichnungen (zehn, hundert, tausend, usw.) zum Einsatz kommen. Die Lösung wird ein bottom-up-Entwurf sein, der das Problem zuerst für sehr einfache Zahlen löst (1-99) und nachfolgend dann diese Lösung in eine Variante für den Bereich von 100-999 einbettet usw.
Zahlen von 1-99
Die Umwandlung für die Zahlen von 1-99 wird von der Funktion convert2 (2 für maximal 2 Stellen) geleistet. Zuerst wird die Zahl in ihre zwei Stellen zerlegt (1er und 10er Stelle) und das Ergebnis in einem Tupel übergeben (digits). Der Einsatz der combine-Funktion auf diesem Tupel errechnet nun die fertige Zeichenkette durch Fallunterscheidung und indizierten Zugriff in Listen vorgefertigter Wörter. Die 1 wird separat behandelt, da sie lediglich alleine "Eins" lautet, ansonsten nur "Ein" wie bei "Einhundert" (Fall (0,1)). Die einstelligen Zahlen >1 (Zwei, Drei usw.) werden direkt in einen entsprechenden Listenzugriff (Fall (0,u+1), Liste units) überführt. Die Zahlen von 10 bis 19 sind Sonderfälle und werden ebenfalls direkt in eine eigene Liste abgebildet (Fall (1,u), Liste teens). Für alle größeren Zahlen wird unterschieden zwischen solchen mit einer Ziffer > 0 auf der ersten Stelle (t+2,u+1) und solchen ohne (t+2,0). Im ersteren Fall werden Zugriffe auf die Listen tens und units kombiniert, um letzteren wird lediglich in die tens-Liste indiziert.
01 -- units sind die einfachen Zahlen, teens sind die Sonder-zahlen von 10 bis 19 und tens sind die Vielfachen von 10
02 units,teens,tens :: [String]
03 units = ["Ein","Zwei","Drei","Vier","Fuenf","Sechs","Sieben","Acht", "Neun"]
04 teens = ["Zehn","Elf","Zwoelf","Dreizehn","Vierzehn","Fuenfzehn","Sechszehn","Siebzehn","Achtzehn","Neunzehn"]
05 tens = ["Zwanzig","Dreißig","Vierzig","Fuenfzig","Sechzig","Siebzig","Achtzig","Neunzig"]
|
5-1.txt |
Codebeispiel 46
01 -- Konvertieren einer zweistelligen Zahl in einen String
02 convert2 :: Int -> String
03 convert2 = combine2 . digits2
04
05 -- Aufteilen einer Zahl in den /10 teilbaren Anteil und Rest
06 digits2 :: Int -> (Int,Int)
07 digits2 n = (n `div` 10,n `mod` 10)
08
09 -- Fallabhängig in die String-Listen indizieren
10 combine2 :: (Int,Int) -> String
11 combine2 (0,1) = "Eins"
12 combine2 (0,u+1) = units!!u
13 combine2 (1,u) = teens!!u
14 combine2 (t+2,0) = tens!!t
15 combine2 (t+2,u+1) = units!!u ++ "und" ++ tens!!t
|
5-2.txt |
Codebeispiel 47
Zahlen von 1-999
Die Definition der nächsthöheren Konvertierungsfunktion convert3 (Zahlen 1-999, dreistellig) greift wie oben bereits angekündigt auf die Funktion convert2 zurück. Sie zerlegt die Zahl in ihre 100er-Stelle und den Rest. Ist die 100er-Stelle == 0 und der Rest != 0 (0,t+1), so wird die Umwandlung vollständig an die convert2-Funktion deligiert. Existiert lediglich die 100er-Stelle (h+1,0), so wird diese über die units-Liste in einen String umgewandelt. Im Fall (h+1,t+1) existieren sowohl 100er-Stelle als auch Rest und die vorgenannten Funktionen werden kombiniert.
01 -- Konvertieren einer dreistelligen Zahl in einen String
02 convert3 :: Int -> String
03 convert3 = combine3 . digits3
04
05 -- Aufteilen einer Zahl in den /100 teilbaren Anteil und Rest
06 digits3 :: Int -> (Int,Int)
07 digits3 n = (n `div` 100,n `mod` 100)
08
09 -- Fallabhängig in die String-Listen indizieren
10 combine3 :: (Int,Int) -> String
11 combine3 (0,t+1) = convert2 (t+1)
12 combine3 (h+1,0) = units!!h ++ "hundert"
13 combine3 (h+1,t+1) = units!!h ++ "hundert und " ++ convert2 (t+1)
|
5-3.txt |
Codebeispiel 48
Zahlen von 1-999.999
Die Einbeziehung von Tausendern verläuft analog zu convert3, die Zahl wird in ihren Tausenderanteil und den Rest aufgeteilt, die Berechnung der Zeichenfolge für den Rest wird gegebenenfalls an convert3 deligiert. Ein Sonderfall muß für das "und" zwischen der letzten und der vorletzten Zahl eingeführt werden, ist der Rest < 100, so muß das "und" von convert6 selber erzeugt werden (da im Anschluß das letzte Wort folgen wird), ansonsten wird diese Aufgabe implizit an convert3 deligiert.
01 convert 6 -- Konvertieren einer sechsstelligen Zahl
02
03 -- Aufteilen in den /1000 teilbaren Anteil und Rest
04 digits6 :: Int -> (Int,Int)
05 digits6 n = (n `div` 1000,n `mod` 1000)
06
07 -- Fallabhängig in die String-Listen indizieren
08 combine6 :: (Int,Int) -> String
09 combine6 (0,h+1) = convert3 (h+1)
10 combine6 (m+1,0) = convert3 (m+1) ++ "tausend"
11 combine6 (m+1,h+1) = convert3 (m+1) ++ "tausend" ++ link (h+1) ++ convert3 (h+1)
12
13 link :: Int -> String
14 link h = if h < 100 then " und " else " "
15
|
5-4.txt |
Codebeispiel 49
Code generated with AusarbeitungGenerator Version 1.1, weblink