Ik zet ASCII-woorden om in getallen, maar zit vast in een poging ze te decoderen. Hoe te omzetten 1 = a, 2 = b, 28 = ab enz? (psudeocode oke)

Dus ik dacht dat ik mezelf C ++ zou leren, maar ik lijk geen problemen te hebben met de taal, maar ik ben eerlijk gezegd dom.

Dus mijn idee was dit. Als ik a = 1 zeg, b = 2, z = 26, aa = 27 enz., Kan ik woorden toewijzen aan getallen, een booleaanse waarde gebruiken in een hashtabel (bit gemaskeerd natuurlijk) en een O (1) spellingscontrole hebben. Dus dat schrijven is helemaal geen probleem. Mijn algoritme om het te doen, ziet er als volgt uit:

int pos;
word_key_t char_key;
word_key_t key = 0;
const char *raw = word.c_str();

cout << "Entering getKey loop with " << raw << endl;
for (pos = 0; raw[pos] != '\0'; pos++) {
    if (raw[pos] >= 'A' && raw[pos] <= 'Z') {
        char_key = raw[pos] - 'A';
    } else if (raw[pos] >= 'a' && raw[pos] <= 'z') {
        char_key = raw[pos] - 'a';
    } else {
        throw new runtime_error("Unrecognised Character");
    }

    key += (char_key + 1) * (pow(CHARS_IN_ALPHABET, pos));
}

cout << "word: " << raw << " ,score: " << key << endl;
return key;

Het lijkt te werken,

a = 1 b = 2 ab = 53 ac = 79.

Ik geloof dat dit correct is.

Ik heb echter problemen om het te decoderen. Dit is mijn beste poging en het werkt niet. Ik geloof dat ik pow (26, positie) en decrementering vanaf het einde van de string moet gebruiken, maar ik heb er moeite mee om dit te bereiken. Dit is een werkbare zelfstandige code die het verkeerde doet:

#include 
#include 
#include 

typedef uint32_t word_key_t;
const int CHARS_IN_ALPHABET = 26;
const int BUFFER_SIZE = 255; //ignore this for now.

using namespace std;

string reverseKey(const word_key_t key); //broken algo

int main(int argc, char** argv) {
        reverseKey(53);//53 = ab
        return 0;
}

//disassemble a word_key_t into it's original string. returns lowercase only
string reverseKey(const word_key_t key)
{

  char chr, buffer[BUFFER_SIZE];
  word_key_t keyc = key, isolated, pos = BUFFER_SIZE;

  cout << "key: " << keyc << endl;

  while (keyc != 0) {
      isolated = (keyc - 1) % ((word_key_t)CHARS_IN_ALPHABET + 1);
      cout << "key: " << keyc << ", isolated: " << isolated << endl;
      chr = (char)'a' + isolated - 1;
      cout << "isolated character: " << chr << endl;
      keyc = (keyc - isolated)/CHARS_IN_ALPHABET;
      cout << "new key: " << keyc << endl;
      pos++;
  }

  string s("test");
  return s;

}

Als iemand me zou kunnen aanstoten naar de juiste psudeocode om dit op te lossen, zou ik heel dankbaar zijn. Ik ben een beetje gek geworden en verloor de plot met de oplossing. Ik kan het gewoon niet zien. Iets vertelt me ​​aan 2logX/2log26 en ik denk dat ik er gewoon wat slimmere ogen op moet hebben. Dan kan ik weer leren C ++ te leren. "Hier voert u de code in

2
" Ik schijn geen problemen te hebben met de taal, maar ik ben eerlijk gezegd dom " +1 voor het maken van me lol
toegevoegd de auteur ildjarn, de bron
Dit lijkt op het Excel-algoritme "kolomtitel" tot "kolomnummer" ;-) Er zijn op zijn minst een paar SO-vragen die daarmee verband houden, IIRC.
toegevoegd de auteur user166390, de bron
@Philluminati Nee, er zullen wat leuke details antwoorden zijn :)
toegevoegd de auteur user166390, de bron
Ik weet niet zeker of ik "maar" twee keer in dezelfde zin mag gebruiken, maar ik vertrouw niet dat ik het kan repareren zonder nog meer problemen te introduceren.
toegevoegd de auteur Philluminati, de bron
@pst, zojuist een antwoord daarop opgezocht, de code gekopieerd, het werkt perfect. Als je die reactie plaatst als een antwoord. Ik accepteer het. Heel erg bedankt!
toegevoegd de auteur Philluminati, de bron

5 antwoord

Sommige bewerken later. Ik heb de generatie van de sleutelwaarden verkeerd begrepen. Ik denk dat het genereren van de letters van de sleutel zou zijn:

while ( key )
   {
   int char_key = key % 26;
   char c = 'a' + (char)( char_key - 1 );
   key /= CHARS_IN_ALPHABET;      
   }

Hoewel ik nog steeds niet denk dat de oorspronkelijke berekening van de sleutel correct is. Ik geloof nog steeds dat de sleutelberekening moet zijn:

key = CHARS_IN_ALPHABET * key + char_key + 1;

Verwerk de array raw [] in omgekeerde volgorde om te voorkomen dat ze in omgekeerde volgorde worden geëxtraheerd.

2
toegevoegd
Ik denk dat hij het nummer uit de letters correct berekent; hij wil het omgekeerde doen: de letters van het nummer genereren.
toegevoegd de auteur ildjarn, de bron

Je hebt feitelijk een basis-27-nummer (aa = a * 26 + b) maar het vermijden van het gebruik van "nullen".

INPUT: encodedWord such that "aa" = 27, "ab" = 28, etc.
OUTPUT: The ASCII string

outString := ""
While encodedWord > 0 Do
  lastLetter = encodedWord % 27;
  encodedWord = encodedWord/27;
  outString := toChar(lastLetter + 64) + outString;
End-while
Return outString;
1
toegevoegd

Ik zou willen voorstellen geen "power" -functies te gebruiken, in het bijzonder zwevende functies.

De volgende sets 'a' = 0, 'z' = 25, 'aa' = 26 etc en werken alleen met integer optellen, vermenigvuldigen en delen (geen zwevend punt). Er is slechts één vermenigvuldiging vereist per gecodeerd teken en er is slechts één divisie vereist per gedecodeerd teken.

#include 
#include 
#include 
#include 

template 
T encode(const char* s)
{
  T result = 0;
  while (*s != 0)
  {
    result *= 26;
    result += std::tolower(*s) - 'a';
    ++s;
  }
  return result;
}

template 
std::string decode(T x)
{
  std::string s;
  while (x != 0)
  {
    s += x % 26 + 'a';
    x /= 26;
  }
  std::reverse(s.begin(), s.end());
  return s;
}

int main() 
{
  std::cout << decode(encode("tbce")) << std::endl;
}

Ideone-code hier

0
toegevoegd

Uw probleem wordt hervat in een basis naar basisconversie, in uw geval van basis 10 naar basis 26. Het verschil is dat a = 0, b = 1 enzovoort (0 = eerste symbool).

Een andere opmerking is dat je de geconverteerde string niet hebt teruggezet (ba = 53).

Hier is de volledige code (het eerste element is 0, niet 1, d.w.z. = 0)

Net als in uw code, zijn tekens in de geconverteerde tekenreeks niet omgekeerd (alsof ze in een normale base-to-base conversie zouden moeten zijn)

#include 
int power(int x, int times){
    int result = 1;
    while (times--) result *= x;
    return result;
}
void convert(int n, char *s){
    int i = 0;
    do {
        s[i++] = (n % 26) + 'a';
    } while ((n /= 26) > 0);
    s[i] = 0;
}
int convertBack(char *s){
    int i = 0;
    int n = 0;
    while (s[i]) {
        n += ( (s[i]-'a') * power(26, i));
        i++;
    }
    return n;
}
void main(){
    char s[100];
    convert(53, s);
    printf("Converted:%s\n",s);
    printf("Convert back=%d", convertBack(s));
}
0
toegevoegd

Je kunt ruilen met iets meer ruimte, en een betere uitvoeringstijd krijgen door van de basis een macht van 2 te maken (zeg 32 in jouw geval).

Op deze manier kunt u ploegen en logische bewerkingen gebruiken in plaats van vermenigvuldigen, delen en mod.

Bijvoorbeeld:

void convert(int n, char *s){
    int i = 0;
    do {
        s[i++] = (n && 0x1F) + 'a';
    } while ((n >>= 5) > 0);
    s[i] = 0;
}

int convertBack(char *s){
    int i = 0;
    int n = 0;
    while (s[i]) {
        n += ( (s[i]-'a') >> 5*i;
        i++;
    }
    return n;
}

en de main zou hetzelfde moeten zijn als kcsoft suggereerde.

0
toegevoegd