[Source Code] Zahlen als Wort ausgeben

03/21/2016 11:03 Coffee Time#1
Code:
Public Function NumberWord(n As Integer) As String
      Select Case n
         Case Is < Integer.MinValue + 2, Integer.MaxValue
            Throw New ArgumentOutOfRangeException("n", n, String.Format("valid range is: -{0} to {0}", Integer.MaxValue - 1))
         Case 0 : Return "null"
         Case Is < 0 : Return "minus " & NumberWord(-n)
      End Select
      NumberWord = NumberWordRecursive(n)
      Dim zehner, einer As Integer
      zehner = Math.DivRem(n, 10, einer)
      ' "s" anhängen, wenn keine zehner-stelle, und einer = 1 - zB 1, 101, 1001, 2501 ...
      If (zehner Mod 10) = 0 AndAlso einer = 1 Then NumberWord &= "s"
   End Function
   Private Function NumberWordRecursive(n As Integer) As String
      Dim einer = "##invalid ein zwei drei vier fünf sechs sieben acht neun zehn elf zwölf".Split
      Dim zehner = "##invalid zehn zwanzig dreißig vierzig fünfzig sechzig siebzig achzig neunzig".Split
      Dim dimension = {New With {.n = 100, .text = "##invalid"},
                       New With {.n = 1000, .text = "hundert"},
                       New With {.n = 1000000, .text = "tausend"},
                       New With {.n = 1000000000, .text = "millionen"},
                       New With {.n = Integer.MaxValue, .text = "milliarden"}}
      Dim geteilt, rest As Integer
      geteilt = Math.DivRem(n, 10, rest)
      Select Case n
         Case 0 : Return ""
         Case Is < 13 : Return einer(n)
         Case Is < 20 : Return einer(rest) & zehner(1)
         Case Is < 100
            If rest = 0 Then Return zehner(geteilt)
            'wenn Einer da sind, vertauschte Reihenfolge
            Return einer(rest) & "und" & zehner(geteilt)
         Case Else
            Dim i = Array.FindIndex(dimension, Function(itm) n < itm.n)
            geteilt = Math.DivRem(n, dimension(i - 1).n, rest)
            NumberWordRecursive = NumberWordRecursive(geteilt) & dimension(i).text & NumberWordRecursive(rest)
            If i > 2 AndAlso geteilt = 1 Then
               Select Case i 'singular bei millionen/milliarden
                  Case 3
                     NumberWordRecursive = NumberWordRecursive.Remove(10, 2).Insert(3, "e")
                  Case 4
                     NumberWordRecursive = NumberWordRecursive.Remove(12, 1).Insert(3, "e")
               End Select
            End If
      End Select
   End Function
   Private Sub Test()
      ' paar interessante Zahlen
      For Each i In {0, 1, 125, 1000000, 1000000000, 1000100000, 100010000, 101001, 1021, 3333, 1123456, 3123456, Integer.MaxValue - 1}
         Console.WriteLine(NumberWord(i))
      Next
      End
   End Sub
Man könnte auch noch was mit mit Runden, oder mit Nachkommastellen machen.
Ich denke aber, das sollte man eher als abgetrennte Funktion angehen. Etwa Runden hat ja nichts mit Zahlworten zu tun, und wenn man tatsächlich die Cents auf dem Scheck aufführen will, kann man die 2 Nachkommastellen ja nochmal extra durchlaufen lassen.

Am Algo-Konzept hat mich überrascht, wie systematisch die Grammatik eiglich ist, und insbesondere rekursiv: Die Regeln für milliardener, millionener, tausender, hunderter sind immer dieselben.
Und das unregelmäßige Zeugs im Bereich unter hundert wiederholt sich - absolut regelmäßig - auf den höheren Ebenen - Rekursion eben.
ZB um die Zahl 125125125 zu "sagen", wird das Wort "einhundertfünfundzwanzig" drei mal gebildet, und es wird halt "millionen" und "tausend" eingefügt:
einhundertfünfundzwanzigmillioneneinhundertfünfund zwanzigtausendeinhundertfünfundzwanzig

Technisch gesehen setze ich v.a. 2 String-Arrays ein, und ein Array von anonymen Datentypen.

Auch verwende ich die weniger bekannte Math.DivRem() - Methode, eine Art mächtigeres Modulo, weils den Rest der Teilung nicht verfallen lässt.
Und Array.FindIndex() mit anonymer Methode - kennen vmtl. auch nur Leute, die gelegentlich browsen im Framework - mittm ObjectBrowser ;)

Quelle: vb-paradise.de
04/17/2016 00:55 DeinMud#2
nice copy & Paste:

[Only registered and activated users can see links. Click Here To Register...]


(Bin mir absolut sicher dass du nicht "ErfindesDesRades" bist, ansonsten kannst du mich eines besseren belehren)
04/17/2016 16:30 florian0#3
In einem anderen Thread hat er auch zufällig die Quellangabe vergessen und dann nachgebessert: [Only registered and activated users can see links. Click Here To Register...]