Python Wort zu Zahl Algorythmus?

2 Antworten

Analog wie man eine hex-Zahl dekodiert, nur eben mit 2*26=52 Symbolen. Der Einfachheit halber mit a=0...Z=51

Erste Stelle (0..51) + Zweite Stelle * 52 + Dritte Stelle * 52² ...

Andersrum jeweils durch 52 (ganzzahlig) dividieren, der Rest (modulo) gibt den Buchstaben (vom Letzten zum Ersten), solange das Divisionsergebnis nicht 0 ist wiederholen.

Edit: Python kann ich nicht, programmieren musst du selbst :)

Woher ich das weiß:Studium / Ausbildung – Informatiker

mihisu  03.06.2022, 22:33

Den Gedanken hatte ich auch zuerst. Das geht auch in die richtige Richtung. Allerdings hat man dann ein Problem mit führenden 'a'.

"abc" würde 0 * 52² + 1 * 52 + 2 = 54 ergeben.
"bc" würde 1 * 52 + 2 = 54 ergeben.
Beide Strings würden der gleichen Zahl 54 entsprechen.

Umgekehrt würde man bei Umwandeln von 54 zu 1 * 52 + 2 und dann weiter zu "bc" wohl immer "bc" und nicht "abc" erhalten. "abc" und andere Strings mit führenden 'a' würden bei der Zählung also quasi übersprungen werden.

(Man erhält übrigens bei der gewünschten Zählung "abc" ~ 2811 und "bc" ~ 107.)

=====

Wenn man das ins Dezimalsystem übertragen würde (mit 10 statt 52 Ziffern):
Man würde gerne mit...

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, ..., 98, 99, 000, 001, ...

... arbeiten. Allerdings kann man im Dezimalsystem beispielsweise nicht 12 von 012, 0012, etc. unterscheiden, da alles die gleiche Dezimalzahl 12 ist.

0
iQa1x  04.06.2022, 00:38
@mihisu

Dann lasse halt a=1 und rechne mit 53 Symbolen, 0 ist dann halt leer und darf in der "Zahl" dann nicht vorkommen. Theoretisch würde dann sowas wie a0c gehen, d.h. du hast in der numerischen Darstellung "ungültige" Werte drin, die keine sinnvolle Kombination geben.

0
mihisu  04.06.2022, 01:32
@iQa1x

Ja und nein.

Kleines Beispiel, was dich zum weiteren Nachdenken bewegen könnte, wenn du denn möchtest: Was wäre deiner Rechnung nach beispielsweise der 2707-te String bei der Durchzählung? Der Fragesteller möchte ja einen Algorithmus, der die entsprechende Zahl (hier: 2707) den den entsprechenden String (entsprechend des genannten Musters) erhalten. Was wäre das deiner Ansicht nach?

Hinweis, falls benötigt...

  • Bzgl. Basis 52 dargestellt ist 2707 = 1 ⋅ 52² + 0 ⋅ 52 + 3 = (1, 0, 3)₅₂.
  • Bzgl. Basis 53 dargestellt ist 2707 = 51 ⋅ 53 + 2 = (51, 4)₅₃.
  • Wenn man 'a' ~ 1, 'b' ~ 2, etc. identifiziert wäre 'a' ~ 1, 'c' ~ 3, 'd' ~ 4, 'Y' ~ 51.
  • Wenn man 'a' ~ 0, 'b' ~ 1, etc. identifiziert wäre 'b' ~ 1, 'd' ~ 3, 'e' ~ 4, 'Z' ~ 51.

(Auflösung... Dem Muster des Fragestellers nach wäre "Zc" ~ 2707.)

Damit will ich dich keinesfalls ärgern, sondern einfach nur darauf hinweisen, dass die Lösung nicht ganz so trivial ist, wie man vielleicht im ersten Moment vermutet. (Kann auch sein, dass du alles bedacht hast, und ich einfach deinen Kommentar nicht richtig interpretiert habe.)

1
iQa1x  04.06.2022, 02:00
@mihisu

Wenn du Basis 53 nimmt dann auch a=1,..Z=52. 0 gibt es zwar, ist aber eben nur dafür da, "führende" Nullen nicht zu ignorieren. Im Dezimalsystem sind führende Nullen ja auch nicht wirklich darstellbar. 2707 würde dann (51,4) oder Yd. Zc würde eben 53*52+3 = 2759 geben. Aber das hast du ja oben selbst geschrieben. Nachteil der Variante ist eben, dass du Kombinationen bauen kannst, die zwischendrin eine 0 haben, denen kein Zeichen zugeordnet sind, wie halt im vorigen Kommentar angegeben.

So richtig verstehe ich nicht, wie du bei 1..52 mit Basis 52 statt 53 arbeiten willst, aber ich schaue mir das morgen nochmal nüchtern an ;)

0
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
base = len(alphabet)
digit_to_letter = [None]+list(alphabet)
letter_to_digit = dict((l, d) for d, l in enumerate(digit_to_letter))

def number_to_string(number, base=base, digit_to_letter=digit_to_letter):
    if number <= 0:
        raise ValueError("number not positive")
    letters = []
    remainder = number
    while remainder != 0:
        remainder, digit = divmod(remainder, base)
        if digit == 0:
            digit = base
            remainder -= 1
        letters.append(digit_to_letter[digit])
    letters.reverse()
    return("".join(letters))

def string_to_number(string, base=base, letter_to_digit=letter_to_digit):
    digits = [letter_to_digit[letter] for letter in string]
    number = digits[0]
    for digit in digits[1:]:
        number *= base
        number += digit
    return(number)

Beispiele:

number_to_string(1) #liefert "a"
number_to_string(2) #liefert "b"
number_to_string(26) #liefert "z"
number_to_string(27) #liefert "A"
number_to_string(52) #liefert "Z"
number_to_string(53) #liefert "aa"
number_to_string(12345) #liefert "dCu"
string_to_number("a") #liefert 1
string_to_number("b") #liefert 2
string_to_number("z") #liefert 26
string_to_number("A") #liefert 27
string_to_number("Z") #liefert 52
string_to_number("aa") #liefert 53
string_to_number("dCu") #liefert 12345

=========================

Im Grunde ist das so ähnlich wie eine b-adische Darstellung zur Basis 52.

Nur muss man aufpassen, dass man bei einer 52-adischen Darstellung normalerweise die Ziffern 0, 1, 2, 3, 4, ..., 51 hat, man hier aber stattdessen mit 1, 2, 3, 4, ..., 51, 52 als Ziffern arbeiten muss. (Dabei wird 'a' ~ 1, 'b' ~ 2, ..., 'Y' ~ 51, 'Z' ~ 52 identifiziert.)

Wenn man beispielsweise die Zahl 48685 betrachtet, so würde man für die 52-adische Darstellung eigentlich (18, 0, 13) erhalten, da



ist. Jedoch ist die 0 in dieser Darstellung problematisch. Stattdessen brauchen wir die Darstellung



was uns dann (17, 52, 13) und damit dann "qZm" liefert. Im von mir genannten Beispielcode wird das durch die drei Zeilen

        if digit == 0:
            digit = base
            remainder -= 1

erreicht. Wenn man eine 0 bei den Ziffern erhalten würde, nimmt man sich stattdessen eine 52, wofür dann jedoch zum Ausgleich der Rest (remainder) entsprechend reduziert wird, damit am Ende immer noch die gleiche Zahl (number) hat. Man besorgt sich also in solchen Fällen eine Ziffer 52 auf Kosten der höherwertigen Ziffern.

========================

Ich hatte zuerst gedacht, ich könne einfach die Nummer um 1 reduzieren und mit 'a' ~ 0, 'b' ~ 1, ..., 'Y' ~ 50, 'Z' ~ 51 identifizieren und mit der 52-adischen Darstellung arbeiten. Da hätte man dann jedoch das Problem, dass beispielsweise "abc" (0, 1, 2) wäre und "bc" (1, 2) wäre, was beides der Zahl 54 entsprechen würde. So würde man jedoch umgekehrt nie wissen wie viele führende 0-en bzw. führende 'a' man hat und das entsprechend in der Zählung auslassen. Weshalb man stattdessen doch eher mit der abgewandelten Version mit 'a' ~ 1, 'b' ~ 2, ..., 'Y' ~ 51, 'Z' ~ 52 arbeiten muss damit man dieses Problem mit den führenden 0en umgehen kann. (Man muss dann aber dafür sorgen, dass zwischendurch Mitten in der Zahl keine 0en als Ziffern (digits) vorkommen, da man für die 0 keinen entsprechenden Buchstaben hat.)