Tee Off! Zahlen, Wörter, Zahlwörter
Geschrieben von: Bernhard Spuida Die Zeit der Entzugserscheinungen ist vorbei! Wieder wurde ein spannendes Turnier ausgetragen. Es gab immerhin 79 Einsendungen mit einer Spannweite von 1578 bis zu 271 Schlägen. Wie man dem Leaderboard und dem Archiv der Golfliste entnehmen kann war der Kampf an der Spitze recht hart und spannend. Besonders freuen wir uns mit Yvonne Eichner die erste ASP-Golferin begrüssen zu dürfen! Es ist also an der Zeit endlich das vierte Turnier und seine überaus interessanten Lösungen vorzustellen. Die AufgabenstellungWie man von Schecks her kennt (nicht daß ich täglich Unmengen davon kriege) muß der Betrag in Zahlen und Worten darauf stehen. Das gehört natürlich kontrolliert! Eine Zahl kleiner einer (deutschen) Billion (1.000.000.000.000) wird in englischen Zahlworten (um es leichter zu machen) angegeben und ist in Ziffern mit Tausendergruppierung umzuwandeln.
Zahlworte sind: und die Zahlen 1 - 99 auf Englisch. Das Wort 'and' kann vorkommen.
Beispiele Die Zahl in Worten wird als String an Application("input") übergeben, die umgewandelte Zahl wird ebenfalls als String in Application("output") zurückgegeben. Ungültiger Input kommt nicht vor. Das Leaderboard
Im Bunker landeten diesmal Mansur Esmann und Stephan Weikert. Bis zum Turnierende fanden die beiden leider ihre Schäufelchen nicht. Genug der Vorrede, auf zur Vorstellung einiger interessanter Lösungen. Claudius CeterasEine Lösung von Claudius, dem wir unseren Golftester zu verdanken haben. Wie man an dieser Lösung sieht, muß gutes Golf nicht viel Zeit kosten... Schade nur daß er die zweite vorgestellte Lösung nicht mehr einreichen konnte. Mein Posting entstand eine Stunde bevor ich zur Uni musste unter Stress... Nur so ist es zu erklären, daß ich die FormatNumber-Funktion vergessen und selbst implementiert habe... *doh* :-) Hier der Code.... <%Set a=application b="Å¡O§+ÃŽÃi`¾øÃ]LÀ£ÖªqS ¡ ·ê@ƨ l a" for each w in split(a("input")) y=0 for i=1to len(w):y=(y+(i+16)*asc(mid(w,i,1)))mod 256:next p=instr(b,chr(y)) if p<20then q=q+p elseif p<28then q=q+(p-18)*10 elseif p=28then q=q*100 else q=q*10^(3*(p-28)) x=x+q q=0 end if next x=x+q for i=0to 3 r=right(x,3) x=int(x/1000) s="."&r&s if x=0then exit for next a("output")=mid(s,2) %> Der Algorithmus basiert wie Mischas Lösung auf einer Hash-Funktion, die alle vorkommenden Worte (and, one, two, ..., nineteen, twenty, thirty, ..., ninety, hundred, thousand, million, billion) auf eine unterschiedliche Zahl umrechnet... In der Variable b sind dann alle diese Zahlen (außer die fürs "and") als Zeichen mit entsprechendem ASCII-Wert gespeichert... Dann kommt das wichtigste: if p<20then q=q+p elseif p<28then q=q+(p-18)*10 elseif p=28then q=q*100 else q=q*10^(3*(p-28)) x=x+q q=0 end if Für die Positionen 1 bis 19 kann man die Zahl direkt übernehmen... Die nächsten Zahlen sind twenty, thirty, ..., ninety, also müssen sie nach Abzug von 18 mit 10 malgenommen werden... An Position 28 liegt "hundred"..., also wird alles vorher mit 100 multipliziert... Die restlichen Positionen beinhalten thousand, million, billion... Deshalb wird entsprechend multipliziert, aufsummiert in der Variable x und q auf null gesetzt für den nächsten Dreierblock... Die letzte For-Schleife tut die Arbeit von FormatNumber... In der langweiligen Vorlesung dann... Ganz ohne Stress fiel mir natürlich sehr schnell eine kürzere Lösung mit nur 311 Bytes ein... *g* <%Set a=application for each w in split(a("input")) y=0:for i=1to len(w):y=(y+(i+16)*asc(mid(w,i,1)))mod 256:next p=instr("Å¡O§+ÃŽÃi`¾øÃ]LÀ£ÖªqS ¡ ·ê@ƨ l a",chr(y)) if p<20then q=q+p elseif p<28then q=q+(p-18)*10 elseif p=28then q=q*100 else q=q*1e3^(p-28) x=x+q q=0 end if next a("output")=FormatNumber(x+q,0)%> Anmerkungen: was es nicht alles ausmacht, den Sprachumfang von ASP zu kennen... Andererseits sieht man mal wieder daß Unis zu was gut sind :-) Stefan Mayer:Was seine Beschreibung so interessant macht, ist daß er uns den gesamten Weg bis zu seiner respektablen Lösung zeigt: Grundsätzlich vorweg - hier ein paar Worte zu meiner Lösung - bis zum Schluß entwickelte sie sich in 11 Versionen, wobei als neue Version von mir eine gröbere Änderung angenommen wurde. Mein erster Ansatz war: www.google.at - suche nach "VB Text Zahl Umwandeln" - naja, vielleicht gibt's ja einen Befehl, der aus einem Zahlenwort eine Zahl macht. Tja - keine Treffer. Ansatz 2 ging hin und hat aus dem Input ein Array gemacht; blank als Trennzeichen, wo jeder bekannte Text durch die Zahl ersetzt wurde. Anschließend habe ich überall wo "100" gestanden ist, den vorigen Arraywert mit 100 multipliziert und scheiterte an den Millionen, Billionen & co. Nächster Versuch - bzw. die Idee: "Thousand" ist doch der Zahlenblock mal 1000. Also *10^3 plus dem nächsten Zahlenblock. Million selbiges ^6. Ich ersetzte also die Zahlen durch )*10^p+( wobei p wahlweise 3,6 oder 9 war. In weiteren Versuchen wurde der Algorithmus zur Umwandlung in Zahlen immer mehr ausgefeilt - im Schnitt reichten mir 2 Buchstaben zur Ziffernerkennung. Um das Ergebnis zu erhalten, verwendete ich die Eval-Funktion - sowie ein Join um das Array wieder zusammenzubauen und ein paar Replaces. Das ist meine endgültige Lösung (mit Zeilenumbrüchen): 1: <%Set z=Application 2: u=z("Input") 3: for s=0to 10 4: u=replace(u,split("tho~wel~tee~ty~hu~m~b~ ~+*~#~$","~")(s),split("#3$ 12 +10 *10 *100 #6$ #9$ + * +0)*10^ +(0")(s)) 5: u=replace(u,split("one tw th fo fi x se ei ni ten el")(s),s+1) 6: next 7: for p=97to122:u=replace(u,chr(p),g):next 8: z("Output")=FormatNumber(eval("("&u&")"),0,,-1)%>
Und so funktioniert sie: Thats it. Anmerkungen dazu: Schön gegolft! Weiter so, wir sind schon auf Deine Lösungen beim nächsten Turnier gespannt. Mischa LandwehrNun zur ersten der beiden Lösungen die sich den ersten Platz mit 271 teilen: <%Set a=Application i=a("input") For z=0To 26 i=Replace(i,Split(" 1e1t1i1h1v1an1on1wo1wn1four1ff1f1sx1sn1g1nn1ln1wl1y1+un1o1m1b1n1+#1r",1) (z ),Split("+ 1 2 2 4 5 5 6 7 8 9 11 12 0 00+ #3+( #6+( #9+( +10 )*1e 3")(z)) Next a("output")=FormatNumber(Eval("("&i&")"),0)%> Um das Problem zu lösen, habe ich die übergebenen Wörter in einen mathematischen Ausdruck umgewandelt. "one hundred and thirty seven thousand ninety one" kann man z. B. durch "(1*100+3*10+7)*1e3+(9*10+1)" ausdrücken. Das muss man nur mit der Funktion Eval ausführen lassen und anschließend formatieren. Dazu habe ich zwei Arrays erzeugt, in denen festgelegt wurde, was ersetzt werden muss. Anfangs sah das so aus: "one two three four five six seven eight nine ten eleven twelve thir teen een fif twen ty y hundred thousand million billion and" "+1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +3 +10 +10 +5 +2 0 0 *100 )*1e3+( )*1e6+( )*1e9+( +0" Nun ging es ja darum, es möglichst klein zu bekommen und so habe ich erst einmal alle unnötigen Zeichen (e, t, i, h und v) gelöscht bzw. durch ein "" ersetzt - und das " " noch durch ein "+". Wenn man sich die Sache genauer anschaut, so merkt man, daß man außerdem nicht alle Buchstaben ersetzen muß. Z.b. könnte man "housand" stehen lassen. Im obrigen Beispiel wäre damit "(1*100+3*10+7)*1e3+(housand+9*10+1)" raus gekommen. Das geht, da "housand" als Variable aufgefasst wird, und so lange es diese nicht gibt, gibt es auch keinen Fehler. Mit beiden Optimierungen - häufige Zeichen löschen und unnötige stehen lassen - wurde daraus folgendes: " 1e1t1i1h1v1an1on1wo1wn1four1ff1f1sx1sn1g1nn1ln1wl1y1+un1o1m1b1n1+#1r" "+ 1 2 2 4 5 5 6 7 8 9 11 12 0 00+ #3+( #6+( #9+( +10 )*1e 3" Da ich auch das " " ersetzen wollte, musste ich beim ersten String ein Trennzeichen wählen. Die 1 schien mir dafür ideal, da ich sie als Integer an die Split-Funktion übergeben konnte. "1" wären zwei Zeichen mehr gewesen. Anmerken möchte ich noch, daß die 1 als Trennzeichen im Nachhinein eine dumme Idee war, da man sie zu leicht mit einem l verwechselt. Eine 0 wäre deutlich besser gewesen. Anmerkung: Der Ansatz ist ähnlich dem oben gezeigten von Stefan, aber diese Eleganz, diese Reduktion auf das wesentliche! Sehr schön. Johann EngbersKomplett anders als die Lösung von Mischa, aber trotzdem gleich lang bzw. kurz: 1: set b=application 2: for each k in split(b("input")) 3: o=0:for i=1to 9:o=o+asc(right(k,i))*i:next 4: j=instr(".z~nW.HE(o.—.‡2[SwM..Ojq1B#;m“*.",chr(o mod 153))-4 5: if j>21then j=10*j-190 6: if j<0then h=h+1e3^-j*l:j=-l 7: if j=21then j=l*99 8: l=l+j 9: next 10: b("output")=formatnumber(h+l,0)
1: bekannt Anmerkungen dazu: Ebenfalls sehr schön - ein Beweis dafür daß auch im ASP-Golf verschiedene Weg zum Green führen. Interessant sind bei diesem Turnier vor allem die vielen alternativen Ansätze zum Sparen von Zeichen in der Kodierung der Zahlwörter. SchlußbemerkungSo, liebe Golffreunde, das war's wieder einmal vom Golfplatz. Schalten sie sich wieder ein wenn sie das nächste Mal 'Fore!' hören. Verwandte Artikel
3. Loch - Dr. Evils Qualitätskontrolle Links zu anderen SitesWenn Sie jetzt Fragen haben...Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten. Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.
Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.
©2000-2006 AspHeute.com |