Konvertierung: unsigned long -> Folge von Buchstaben.

KkTotheT

Grünschnabel
Hallo zusammen,

ich kaue seit längerem am folgenden Problem. Ich lese eine unsigned long Zahl ein und möchte daraus einen String machen. Aber nicht im Sinne von itoa(), dass die selbe Zahl als String corhanden ist sondern auf der Basis des Alphabets: 0->A, 1->B...26->AA, 27->AB.

Ich habe es mit meinen bescheidenen Mitteln bisher versucht. Dabei kommen jedoch stlilistisch grauenvolle, nicht beliebig erweiterbare Lösungen des Problems.

Wie könnte ich dieses Problem geschickt angehen?!


MfG
 
moin


Vielleicht wäre es sinnvoll dies auf der Basis eines 26. Zahlensystems zu errechnen.
Interessiert mich ob das funktioniert, werde das gleich mal versuchen.


mfg
umbrasaxum
 
Ahh ich habs... ich hab schon ne Funktion die das macht hab das mal eben aus einer Klasse gezogen. An der einen Stelle kannst du noch eine Fehlerbehandlung einfügen.
Der "Trick" war das +1 in dem Beispiel.

Code:
#include <iostream>
#include <algorithm>
#include <exception>
#include <string>

std::string numerative_convert(unsigned long  value, std::string const& ciphers)
{
	// Basis des neuen Systems
	unsigned int base = static_cast<unsigned int>(ciphers.length());
	// Wenn keine oder zu wenig Zeichen als Ziffervorrat
	if(base < 2)
		throw std::invalid_argument(std::string("At least 2 different ciphers are requiered."));
	
	// Wenn Wert Null
	if(!value)
		return std::string(ciphers[0],1);

	// Ergebnisstring
	std::string erg;
	// Umwandlung
	while(value > 0)
	{
		// Neues Zeichen am Anfang einfügen
		erg.insert(std::string::size_type(0), 1, ciphers[value % base]);
		value /= base;
	}

	// Zurückgeben
	return erg;
}

int main()
{
	unsigned long wert;
	std::cin >> wert;
	std::cout << numerative_convert(wert+1, std::string("0ABCDEFGHIJKLMNOPQRStUVXYZ"));
}

edit: perfektioniert ;-) Damals war ich noch jung und unerfahren^^
 
Zuletzt bearbeitet:
Tobias K. hat gesagt.:
moin


@FireFlow
Also so richtig funktioniert das aber nicht....


mfg
umbrasaxum

Was meinst du damit? Wann funktioniert es nicht? Bei mir gehts... Ich hatte nur noch vor ein paar min ein Fehler drin weil ich da was mit den lokalen Variablen in der Funktion verwechselt hab (ist wie gesagt aus einer Klasse)

Dann hab ich aber auch noch ne kurze Frage:
Warum geht das hier nicht:
Code:
std::string test;
/* ... */
std::unique(test.begin(), test.end());
Der Compiler (MSVC2003) meckert dass er irgendwo eine L-Value haben will (ist in der Funktion unique)
 
moin



Also dein kleiner 2 Zeilen Codeschnippsel läuft bei mir ohne Probleme.

1. Fehler beim anderen Code war das das W fehltaber das ist mir auch jetzt erst aufgefallen.
2. Bevor es eine Stelle mehr gibt kommt z.B. A0 also bei er 26, 53, ....


mfg
umbrasaxum
 
Oh man ich Depp... Weiß nun warum das mit dem unique net ging. Ich wollte es oben in der Funktion anwenden aber da hab ich ja den String als konstante Referenz... *d'oh*
 
@FireFlow: dein Programm funktioniert aber tatsächlich nicht so wie es soll. Für die Zahl 26 bekomme ich z.B. A0 (hätte AA sein sollen) und für 27 dann AA (hätte AB sein sollen).

Ganz so einfach ist es nämlich nicht, aber seht doch selbst.
Code:
        // Ergebnisstring                                                                                                               
        std::string erg( 1, ciphers[value % base]);

        // Umwandlung                                                                                                                   
  
        if (value > 0) {
          value /= base++;
          while(value > 0) {
            unsigned int rest = value % base;

            erg.insert(std::string::size_type(0), 1, ciphers[std::max(1U, rest) - 1]);

            value /= base;
          }
        }
        return erg;
     /* ... */
    const std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    std::cout << numerative_convert(wert, alphabet) << std::endl;

Der Trick ist nämlich die +1 beim Funktionsaufruf wegzulassen ;-)
 
Mist, zu früh gefreut. Mein Programm funktioniert dann irgendwann auch nicht mehr so wie es soll. Ich hab's gerade mal mit "abc" als Buchstabenmenge probiert und für die Zahl 15 kommt "aaa" raus, sollte aber eigentlich "aba" sein und später wird's noch gräuslicher. Hm. :mad:
 
So, es hat mir doch keine Ruhe gelassen und da ich hab mich mal hingesetzt und hab mir die Sache richtig überlegt. Durch trial-and-error kam man ja offensichtlich nicht weiter.

Also, die Bildungsvorschrift für eine solche Zahl ist:

Code:
x = [ n^i*(1+x[i]) + n^(i-1)*(1+x[i-1])+ ... + n*(1+x[1]) + 1*(1+x[0]) ] - 1
Wobei n die Basis ist und x[k] die Wertigkeit des jeweiligen Buchstabens an der Stelle k in einem String wie z.B. "ACB" (die Stellen fangen logischerweise rechts mit 0 an).

Da kommt man mit der Integer-Division und Modulo-Operation nicht zu Rande.
Code:
#include <algorithm>
#include <exception>
#include <string>

#include <cassert>

std::string num2alpha (unsigned long value, std::string const& digits)
{
	assert (digits.length() > 1);
	
	std::string erg;
	
	const unsigned int base = static_cast<unsigned int>(digits.length());
#ifndef NDEBUG
	const unsigned long old_value = value;
#endif // NDEBUG

	unsigned long n = 0, power = 1;

	++value;
	
	while ( n + power * (base + 1) <= value ) {
		n += power;
		power *= base;
	}

	while (power > 0) {
		assert( value >= power + n );
		
		unsigned int xi = (value - n) / power;
		
		erg += digits.at(xi-1);
		
		value -= xi * power;

		n -= power /= base;
	}
	assert( alpha2num ( erg, digits) == old_value );
	
	return erg;
}

const std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::cout <<  num2alpha (wert, alphabet) << std::endl;
Diesmal sollte es aber stimmen. Zumindest bis 10.000 hab ich es auch überprüft.

Die Implementierung der "alpha2num" Funktion bleibt als Übung dem Leser überlassen. ;)
 
Zurück