Excel Column in eine Nummer

moritzBremen

Mitglied
servus, ich habe einen fertigen code gefunden im Internet und würde ihn gerne verstehen nur leider komme ich nicht weiter. Dabei geht es darum das man eine Excel Reihennummer bekommt und diesen in eine zahl umwandeln soll nur kapier ich die rechnung nicht ganz. Man bekommt zum Beispiel parameter AA und es soll 27 kommen. Könnte mir jemand die rechnung erklären?

1673548083408.png
 

KonradN

Super-Moderator
Mitarbeiter
Das Geheimnis ist, dass ein char auch nur eine 16Bit Zahl ist. Daher kann man mit char Werten auch rechnen.
'A' ist also der 16Bit Code, mit dem das Zeichen A dargestellt wird. (65 bzw. 0x41 wenn man es Hexadezimal schreiben will)

Die Columns sind ja A, B, C, D, ....

Also ist 'A' -> 1
'B' -> 2
u.s.w.

Unabhängig, welcher Wert nun 'A' hat:
'A' - 'A' ist 0.
'B' - 'A' ist 1, ....

Das sind schon fast die gewünschten Werte - nur eben 1 zu klein. Daher noch ein +1

Jetzt fehlt nur noch dsa result *= 26

Wenn es mehr wie 26 Elemente gibt, dann geht es weiter: Nach "Z" kommt "AA".

Hier ist das Verständnis des Zahlensystems wichtig: Im Dezimalsystem hast Du bei der Zahl 123 ja:
( (1*10 + 2) * 10 ) + 3

Von Ziffer zu Ziffer wird also immer erst mit der Anzahl der Möglichkeiten multipliziert und dann die Ziffer addiert. Also ausführlich:
erst 1
dann 1*10 + 2
Dann 12 * 10 + 3

Die Anzahl der Möglichkeiten ist nun aber 26. Also haben wir bei "AB" z.B.
erst haben wir als Ergebnis 0 - noch keine Ziffer ausgewertet.
Dann gehen wir die erste Ziffer an (index 0) und rechnen erst Ergebnis * 26 -> immer noch 0. Und dann addieren wir den Wert dazu: A war 1 also 1
Dann gehen wir zur nächsten Ziffer (Index 1) und rechnen erst Ergebnis * 26 -> 1*26 = 16. Und dann addieren wir den Wert dazu: B war 2 also 26+2 = 28.

Und nun können wir prüfen:
A -> 1
B -> 2
...
Z -> 26
AA->27
AB->28 <-- Das war ja auch unser Ergebnis, also die Kontrolle zeigt, dass es richtig zu sein scheint.
 

moritzBremen

Mitglied
Vielen Dank für die Antwort! Beim Gegenteil sprich man beim rückrechnen ist es dann komplett andersrum ? Zum Beispiel eine Zahl in eine hex zahl kodieren lautet dann die Funktion so: leider kapier ich dies nicht ganz haben sie da eine Ahnung? Freundliche Grüße Moritz

while (nummer= 0) {
nummer--;
rest = (int) nummer % 16;
nummer = Math.floor(nummer/ 16);
ergebnis.add(0, hex[rest]);
}
 

KonradN

Super-Moderator
Mitarbeiter
Also bei dem Code sind mehrere Dinge falsch:
a) die While schleife soll doch so lange laufen, wie nummer > 0 ist. Sprich: nummer == 0 wäre eine Abbruchbedingung.
b) nummer = 0 wäre auch kein Vergleich sondern eine Zuweisung.

Dann hast Du da jetzt keine Umwandllung einer Zahl in eine Excel Spaltenbezeichnung sondern statt dessen wanelt der Code (von den Fehlern mal abgesehen) eine Zahl in eine Hexadezimal-Zahl um.
 

moritzBremen

Mitglied
Mein Fehler die while bedingung lautet nummer !=0. Anscheind funktioniert der code richtig ich habe leider schwierigkeiten ihn zu verstehen zum Beispeil die erste zeile in der while loop nummer--; da kann ich mir nix drunter vorstellen
 

KonradN

Super-Moderator
Mitarbeiter
Wenn Du Dir anschaust, was in die andere Richtung gemacht wurde: Da gab es ja das +1.

Wenn Du nun in die andere Richtung alles rechnen willst, dann bedeutet es, dass man erst 1 abziehen muss.

Das ist also einfache Mathematik: Wenn a +1 = b ist und nun will man mit b eben a ausrechnen, dann stellt man es um und erhält a = b -1.

Aber noch einmal - der Code ist eben nicht die umkehr des Codes in diesem Thread! In diesem Thread wurden Excel Spaltenbezeichner in Werte gerechnet. Und dein Code rechnet mit Hexadezimal-Zahlen. Das sind zwei unterschiedliche Dinge.
 

moritzBremen

Mitglied
Bedeutet das, dass die -1 sozusagen wieder wie beim entkodieren dieses eine Problem mit 0=A 1=B behebt? In diesem Fall wäre dann szg. 2=A 3=B und durch das -1 wird es korrigiert zu 1=A 2=B?
 
Es ginge auch mit der Methode Integer.parseInt( ), wenn kein 'Z' enthalten ist:

Java:
    public static void main(String[] args) {
        String alphabet = "123456789";
        for (int i = 'A'; i <= 'Z' - 9; i++) {
            alphabet += (char) i;
        }
        String finalAlphabet = alphabet;
        System.out.println("finalAlphabet = " + finalAlphabet);
        String col1 = "ABC"; // Darf kein 'Z' enthalten
        System.out.println("col1 = " + col1);
        String col2 = col1.chars().mapToObj(i -> String.valueOf(finalAlphabet.charAt(i - 'A'))).collect(Collectors.joining());
        System.out.println("col2 = " + col2);
        int intVal = Integer.parseInt(col2, finalAlphabet.length());
        System.out.println("intVal = " + intVal);
    }

Code:
finalAlphabet = 123456789ABCDEFGHIJKLMNOPQ
col1 = ABC
col2 = 123
intVal = 731

Weiß gar nicht genau, ob Excel bis Z geht...
 

KonradN

Super-Moderator
Mitarbeiter
Sorry, aber was soll so ein Post?
a) es geht schon nicht mehr um das Problem, aus den Spaltenbezeichnngen den index zu berechnen.
b) Wenn man die Problemstellung nicht einmal verstanden hat, wie groß ist die Chance, dass da was sinnvolles heraus kommt?
c) Wenn ein Anfänger Probleme hat, einen einfachen Java Code zu verstehen: Wie sinnvoll ist es da in Deinen Augen, dem einen anderen Code ohne Dokumentation mit Strams zu geben?
Nein - ich erwarte da keine Antwort.

Weiß gar nicht genau, ob Excel bis Z geht...
Nein, Excel geht deutlich über da Z hinaus. Nach dem "Z" würde es mit "AA" weiter gehen ... und nach dem "ZZ" mit AAA u.s.w.
Und es gibt kein

Bedeutet das, dass die -1 sozusagen wieder wie beim entkodieren dieses eine Problem mit 0=A 1=B behebt? In diesem Fall wäre dann szg. 2=A 3=B und durch das -1 wird es korrigiert zu 1=A 2=B?
Da ist erst einmal die Frage, was denn da überhaupt gemacht werden soll. Noch einmal: Das ist NICHT die Umkehrung des Codes aus #1! Das erkennst Du schon daran, dass hier mit 16 gerechnet wird und in #1 mit 26. Und was mich auch wundert: number ist keine ganze Zahl sondern eine Fließkommazahl. Das macht es auch noch etwas dubioser.
 

moritzBremen

Mitglied
Sorry, aber was soll so ein Post?
a) es geht schon nicht mehr um das Problem, aus den Spaltenbezeichnngen den index zu berechnen.
b) Wenn man die Problemstellung nicht einmal verstanden hat, wie groß ist die Chance, dass da was sinnvolles heraus kommt?
c) Wenn ein Anfänger Probleme hat, einen einfachen Java Code zu verstehen: Wie sinnvoll ist es da in Deinen Augen, dem einen anderen Code ohne Dokumentation mit Strams zu geben?
Nein - ich erwarte da keine Antwort.


Nein, Excel geht deutlich über da Z hinaus. Nach dem "Z" würde es mit "AA" weiter gehen ... und nach dem "ZZ" mit AAA u.s.w.
Und es gibt kein


Da ist erst einmal die Frage, was denn da überhaupt gemacht werden soll. Noch einmal: Das ist NICHT die Umkehrung des Codes aus #1! Das erkennst Du schon daran, dass hier mit 16 gerechnet wird und in #1 mit 26. Und was mich auch wundert: number ist keine ganze Zahl sondern eine Fließkommazahl. Das macht es auch noch etwas dubioser.
Danke für Ihre Antworten! Mir ist bewusst das es sich gerade nicht um die Basis 26 handelt. Die 26 hab ich mittlerweile dank Ihrer Erklärung und üben verstanden! Ich wollte das kodieren nochmal verstehen bei der basis 16 handelt es sich ja um hex zahlen sprich man verwandelt zahlen in hex spaltennummern. Tut mir leid hätte ich ein bisschen genauer beschreiben sollen. Bei der hex kodierung wunder ich mich warum man -1 macht. Mir ist bewusst das es einfach eine Umkehrung vom Dekodieren aber so ganz Klick hat es leider noch nicht gemacht. Was das % und / ist mir klar. % macht man um den Rest rauszukriegen dieser Rest ist dann auch die gewünschte zahl im gewünschten zahlensystem sprich hier bei uns hexa anschließend kommt die / um die nächste Ziffer zu betrachen so ähnlich wie beim dekodieren mit dem * nur halt andersrum (ich hoffe diese erklärung ist richtig :D) und dieses -1 würde ich mit dem aktuellen wissensstand so erklären wie beim dekodieren nur anders rum statt + machen wir - dass das mit den buchstaben wieder passt
 

KonradN

Super-Moderator
Mitarbeiter
Das Problem mit dem -1 bzw -- Operator ist bei den Excel Spalten, weil wir ein System haben, das ab 1 losgeht.

A ist 1.
Z ist 26.

Also wenn man da eine Zahl hat, dann müssen wir von der Zahl erst 1 abziehen und dann %26 rechnen.
1 - 1 = 0. => 'A' + 0 = 'A'
26 - 1 = 25. => 'A' + 25 = 'Z'

AA soll 27 sein. Also rückwärts gerechnet:
27 -1 = 26. Dann 26 % 26 = 0 ==> 'A' + 0 = 'A'
Weiter zu betrachten: 26 / 26 = 1.
Bei der 1 dann wieder:
1 - 1 = 0. ==> 'A' + 0 = 'A' ==> "AA" kommt da raus.

Dieses -1 wird aber nur notwendig, weil wir sozusagen ein Zahlensystem haben, das keine "0" kennt.

Daher ist das bei dem Hexadezimalen Zahlen nicht mehr so. Da haben wir eine 0:

0 -> 0
1 -> 1
...
9 -> 9
10 -> A
11 -> B
15 -> F
16 -> 10
...

Dadurch braucht man keine -1 mehr. Wenn ich also die 54 Dezimal in Hexadezimal haben will, dann rechne ich kein -1 sondern rechne das Module direkt mit der ursprünglichen Zahl:
54 % 16 = 6
Weiter zu betrachten: 54 / 16 = 3

die 54 ist somit 0x36

Und der Unterschied ist hier, dass wir eine 0 haben!
 

KonradN

Super-Moderator
Mitarbeiter
Vielen Dank! Tatsächlich braucht man bei hex auch -1 da sonst das ergebnis falsch ist :/
Das ist jetzt für mich gerade nicht nachvollziehbar. Kannst Du da mal den ganzen Code zeigen, also inclusive dem Array hex und dem Code, wie er gerade bei Dir funktioniert?

Die eigentliche Umwandlung von reinen Zahlen wäre rein mit % und / zu machen - ohne eine 1 abzuziehen. Daher ist das gerade irritierend.
 

KonradN

Super-Moderator
Mitarbeiter
Also nur um meine Irritation zu erklären: Ich habe mir einmal angeschaut, was man da so an Ergebnissen bekommt. Dazu habe ich Deinen Code einfach einmal genommen und minimal imgeschrieben:

Java:
    public String translateToHex(int number) {
        String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
        int rest;
        String ergebnis = "";
        while (number > 0) {
            number--;
            rest = number % 16;
            number = number/ 16;
            ergebnis = hex[rest] + ergebnis;
        }
        return ergebnis;
    }

Das habe ich dann einfach einmal getestet (Die Zahlen habe ich in der Hexadezimalen Schreibweise angegeben - das macht es besser lesbar!):
Java:
    @ParameterizedTest
    @CsvSource({
            "0x01, 1",
            "0x0f, F",
            "0x10, 10",
            "0x20, 20",
    })
    public void testTranslateToHex(int number, String result) {
        assertEquals(result, translateToHex(number));
    }

Und das kommt so nicht hin. Schauen wir es uns einfach einmal an:

bei 0x01 (1) kam 0
bei 0x0f (15) kam E
bei 0x10 (16) kam F
bei 0x20 (32) kam 0F

Man erkennt an diesen Tests, dass es ein Schema gibt: Die Ziffer ist immer eins zu klein. Also kann man dann ja die hex Tabelle um eins verschieben, also statt mit der 0 fangen wir mit der 1 an. Um den Effekt zu sehen nehme ich die "0", einfach einmal ganz raus und starte den Test erneut.

Die ersten Tests laufen nun durch. Aber die 0x10 und 0x20 kriegen jetzt eine Index out of bounds Exception.

Generell funktioniert es - es darf nur keine 0 vorkommen, denn die haben wir ja raus geworfen.

Also wenn wir die Tests erweitern:
Java:
    @ParameterizedTest
    @CsvSource({
            "0x01, 1",
            "0x0f, F",
            "0x11, 11",
            "0x1F, 1F",
            "0x7F, 7F",
            "0x10, 10",
            "0x20, 20",
            "0x201, 201"
    })
    public void testTranslateToHex(int number, String result) {
        assertEquals(result, translateToHex(number));
    }

Alle Tests ohne eine 0 in der Zahl laufen durch (führende 0er zählen natürlich nicht wie bei 0x01). Also 1, F, 11, 1F, 7F funktionieren, aber 10, 20, 201 - die Tests funktionieren nicht wegen der fehlenden Stelle. Und das Problem ist: Da gibt es nichts, das man eintragen könnte. Da könnte man zwar eine 0 setzen, aber der Wert wäre falsch, denn dann wäre aus 0x10 eben ein "0" geworden.

Daher fürchte ich, dass der Algorithmus von Dir nicht funktioniert und Du vermutlich nur Zahlen getestet hast, die in der Hexadezimalen Form keine 0 enthalten haben!
 
Mir ist doch noch eine Möglichkeit eingefallen, wie es mit der gegebenen parseInt( ) Methode und einer Ergänzung funktionieren würde:

Java:
    public static int convertColumnIndexOneBasedToIntWithParseIntMethod(String col) {

        System.out.println("col = " + col);

        String alphabet = "0123456789ABCDEFGHIJKLMNOP";
        StringBuilder col2 = new StringBuilder();
        for (char c : col.toCharArray()) {
            col2.append(alphabet.charAt(c - 'A'));
        }
        int val = Integer.parseInt(col2.toString(), alphabet.length());
        int add = 1;
        for (int i = 0; i < col.length(); i++) {
            val += add;
            add *= alphabet.length();
        }

        System.out.println("val = " + val);

        return val;
    }

    public static void main(String[] args) {
        convertColumnIndexOneBasedToIntWithParseIntMethod("A");
        convertColumnIndexOneBasedToIntWithParseIntMethod("AA");
        convertColumnIndexOneBasedToIntWithParseIntMethod("AB");
        convertColumnIndexOneBasedToIntWithParseIntMethod("BA");
        convertColumnIndexOneBasedToIntWithParseIntMethod("Z");
        convertColumnIndexOneBasedToIntWithParseIntMethod("ZZ");
    }

Code:
col = A
val = 1
col = AA
val = 27
col = AB
val = 28
col = BA
val = 53
col = Z
val = 26
col = ZZ
val = 702

Man muss also noch für jede Stelle 1,26,676,17576,usw. addieren. Aus meiner Sicht, wäre das ok.
 

KonradN

Super-Moderator
Mitarbeiter
Du hast in Zeile 8 bereits die Position über die Subtraktion des A Wertes.

Statt den Wert zu benutzen, holst Du Dir erst ein Zeichen aus dem Alphabet um dann mit Parseint wieder zu dem Index zu kommen.

Da wäre es einfacher, einfach das Ergebnis der Berechnung aus Zeile 8 direkt zu nutzen.
 

moritzBremen

Mitglied
Also nur um meine Irritation zu erklären: Ich habe mir einmal angeschaut, was man da so an Ergebnissen bekommt. Dazu habe ich Deinen Code einfach einmal genommen und minimal imgeschrieben:

Java:
    public String translateToHex(int number) {
        String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
        int rest;
        String ergebnis = "";
        while (number > 0) {
            number--;
            rest = number % 16;
            number = number/ 16;
            ergebnis = hex[rest] + ergebnis;
        }
        return ergebnis;
    }

Das habe ich dann einfach einmal getestet (Die Zahlen habe ich in der Hexadezimalen Schreibweise angegeben - das macht es besser lesbar!):
Java:
    @ParameterizedTest
    @CsvSource({
            "0x01, 1",
            "0x0f, F",
            "0x10, 10",
            "0x20, 20",
    })
    public void testTranslateToHex(int number, String result) {
        assertEquals(result, translateToHex(number));
    }

Und das kommt so nicht hin. Schauen wir es uns einfach einmal an:

bei 0x01 (1) kam 0
bei 0x0f (15) kam E
bei 0x10 (16) kam F
bei 0x20 (32) kam 0F

Man erkennt an diesen Tests, dass es ein Schema gibt: Die Ziffer ist immer eins zu klein. Also kann man dann ja die hex Tabelle um eins verschieben, also statt mit der 0 fangen wir mit der 1 an. Um den Effekt zu sehen nehme ich die "0", einfach einmal ganz raus und starte den Test erneut.

Die ersten Tests laufen nun durch. Aber die 0x10 und 0x20 kriegen jetzt eine Index out of bounds Exception.

Generell funktioniert es - es darf nur keine 0 vorkommen, denn die haben wir ja raus geworfen.

Also wenn wir die Tests erweitern:
Java:
    @ParameterizedTest
    @CsvSource({
            "0x01, 1",
            "0x0f, F",
            "0x11, 11",
            "0x1F, 1F",
            "0x7F, 7F",
            "0x10, 10",
            "0x20, 20",
            "0x201, 201"
    })
    public void testTranslateToHex(int number, String result) {
        assertEquals(result, translateToHex(number));
    }

Alle Tests ohne eine 0 in der Zahl laufen durch (führende 0er zählen natürlich nicht wie bei 0x01). Also 1, F, 11, 1F, 7F funktionieren, aber 10, 20, 201 - die Tests funktionieren nicht wegen der fehlenden Stelle. Und das Problem ist: Da gibt es nichts, das man eintragen könnte. Da könnte man zwar eine 0 setzen, aber der Wert wäre falsch, denn dann wäre aus 0x10 eben ein "0" geworden.

Daher fürchte ich, dass der Algorithmus von Dir nicht funktioniert und Du vermutlich nur Zahlen getestet hast, die in der Hexadezimalen Form keine 0 enthalten haben!
Wenn ich zum Beispiel in die Methode die Zahl 1 reinstecke müsste 0 rauskommen ohne dieses -- kommt aber eine 1 raus -> falsches Ergebnis
Bedeutet das dann wie Sie es beschrieben haben das es mit dem -- klappt aber sobald der Parameter 0 ist schlägt es fehl?
 

KonradN

Super-Moderator
Mitarbeiter
Wieso soll bei 1 eine 0 heraus kommen?

Die genaue Anforderung hast du in keiner Weise beschrieben. Evtl. willst du das einmal nachholen. Was soll der Code genau machen?

Eine Umwandlung in eine hexadezimale Zahl würde bedeuten, dass die 1 zu einer 1 würde.
 

moritzBremen

Mitglied
Wieso soll bei 1 eine 0 heraus kommen?

Die genaue Anforderung hast du in keiner Weise beschrieben. Evtl. willst du das einmal nachholen. Was soll der Code genau machen?

Eine Umwandlung in eine hexadezimale Zahl würde bedeuten, dass die 1 zu einer 1 würde.
Das kann ich dir leider nicht so genau sagen, da ich das nur spontan im Internet gefunden habe und in meiner Freizeit bisschen java lerne. Liegt es vielleicht daran, dass es hier nicht um die normale umrechnung von zahlensystem geht sondern um excel? Also die bijektive Darstellung
 

KonradN

Super-Moderator
Mitarbeiter
Der Code aus #1 ist ok. Es geht um den Code in #3.

Da geht es nicht mehr um die Spaltenbezeichner in Excel. Wo hast du den Code denn gefunden? Der Code macht so keinen Sinn aus meiner Sicht. Das 1 abziehen von der weiter zu nutzenden Zahl macht wenig bis keinen Sinn. Das habe ich sogar noch einmal bestätigt durch den Test.
 

moritzBremen

Mitglied
Bei #3 geht es ja um die kodierung in eine excelspalte oder irre ich mich ?

#1 Wir kriegen excelspalte und müssen es in die gewünschte base ändern
#3 genau andersrum wir kriegen gewünschte base und müssen es in eine excelspalte kodieren
 

KonradN

Super-Moderator
Mitarbeiter
Nein, denn dann müssten wir ja Werte von A-Z und dann AA-ZZ u.s.w bekommen. Das wären dann aber immer 26 Möglichkeiten und nichts mit 16 wie das %16 bei dem Code hat.
 

KonradN

Super-Moderator
Mitarbeiter
Wenn man die Umwandlung zu Excel Spaltenbezeichnungen haben will, dann wäre das wohl dieser Code:
Java:
    public String translateToHex(int number) {
        int rest;
        String ergebnis = "";
        while (number > 0) {
            number--;
            rest = number % 26;
            number = number / 26;
            ergebnis = ((char)(rest + 'A')) + ergebnis;
        }
        return ergebnis;
    }

Du erkennst, dass statt 16 da mit 26 gerechnet wird. Das number-- ist hier dann tatsächlich notwendig.

Und man braucht keinerlei Tabelle - man hat ja in den chars die werte von 'A' - 'Z' bereits, so dass man da halt mit rechnen kann. Hier ist dann aber noch ein cast zurück zu char notwendig, denn Java rechnet hier mit int Werten.
 

KonradN

Super-Moderator
Mitarbeiter
Wieso base 16? Was genau willst Du denn da haben?

Excel nutzt Buchstaben. Das sind keine Zahlen im Sinne eines Zahlensystems. Ein Zahlensystem zu irgend einer Basis hat einen 0-Wert. Das hat die Excel-Notation mit Buchstaben aber eben nicht.

Das ist also explizit keine Umwandlung zwischen Zahlensystemen. Wenn Du Hexadezimale Zahlen umwandeln wolltest hättest Du ja die Umwandlung von
0 -> 0
1 - > 1
..
15 -> F
16 -> 10
...

Bei dem Wechsel erkennst Du, dass es eben nicht mit "00" weiter geht oder so.

Die Umrechnung in ein anderes Zahlensystem hat daher eben nicht diesen Abzug von 1.

Du vermischt das und das irritiert mich. Und daher die Nachfrage, was Du da erreichen willst.
 

Neue Themen


Oben