Grundkonvertierung mit Strings

16

Einführung

Wir haben hier in der Vergangenheit einige grundlegende Konvertierungsprobleme, aber nicht viele, die darauf ausgelegt sind, Zahlen beliebiger Länge (dh Zahlen, die lang genug sind, dass sie den Datentyp Integer überlaufen) zu bewältigen, und die meisten davon fühlten sich ein wenig kompliziert. Ich bin neugierig, wie sich eine Änderung des Basiscodes auswirken kann.

Herausforderung

Schreiben Sie ein Programm oder eine Funktion in der Sprache Ihrer Wahl, die eine Zeichenfolge einer Basis in eine Zeichenfolge einer anderen Basis konvertieren kann. Die Eingabe sollte aus der umzusetzenden Zahl (Zeichenfolge), der Basis (Basis-10-Zahl), der Basis (Basis-10-Zahl) und dem Zeichensatz (Zeichenfolge) bestehen. Die Ausgabe sollte die konvertierte Zahl (Zeichenfolge) sein.

Einige weitere Details und Regeln lauten wie folgt:

  • Die zu konvertierende Zahl ist eine nicht negative ganze Zahl (seit - und .möglicherweise im Zeichensatz enthalten). So wird auch die Ausgabe sein.
  • Führende Nullen (das erste Zeichen im Zeichensatz) sollten abgeschnitten werden. Wenn das Ergebnis Null ist, sollte eine einzelne Nullstelle verbleiben.
  • Der minimal unterstützte Basisbereich liegt zwischen 2 und 95 und besteht aus den druckbaren ASCII-Zeichen.
  • Die Eingabe für die zu konvertierende Zahl, der Zeichensatz und die Ausgabe müssen alle vom Datentyp string sein. Die Basen müssen vom Integer-Datentyp base-10 (oder Integer-Floats) sein.
  • Die Länge der eingegebenen Zahlenfolge kann sehr groß sein. Es ist schwer, ein vernünftiges Minimum zu quantifizieren, aber erwarten Sie, dass es in der Lage ist, mindestens 1000 Zeichen zu verarbeiten und 100 Zeichen in weniger als 10 Sekunden auf einem anständigen Computer einzugeben (sehr großzügig für diese Art von Problem, aber ich möchte nicht Geschwindigkeit im Mittelpunkt stehen).
  • Sie können keine integrierten Funktionen zum Ändern der Basis verwenden.
  • Die Zeichensatzeingabe kann in beliebiger Anordnung erfolgen, nicht nur die typischen 0-9a-z ... etc.
  • Es sei angenommen, dass nur gültige Eingaben verwendet werden. Sorgen Sie sich nicht um Fehlerbehandlung.

Der Gewinner wird anhand des kürzesten Codes ermittelt, der die Kriterien erfüllt. Sie werden in mindestens 7 Basis-10-Tagen ausgewählt, oder wenn / wenn es genügend Einreichungen gegeben hat. Bei einem Unentschieden gewinnt der Code, der schneller läuft. Wenn die Geschwindigkeit / Leistung nahe genug ist, gewinnt die Antwort, die früher kam.

Beispiele

Hier sind einige Beispiele für Ein- und Ausgaben, die Ihr Code verarbeiten sollte:

F("1010101", 2, 10, "0123456789")
> 85

F("0001010101", 2, 10, "0123456789")
> 85

F("85", 10, 2, "0123456789")
> 1010101

F("1010101", 10, 2, "0123456789")
> 11110110100110110101

F("bababab", 2, 10, "abcdefghij")
> if

F("10", 3, 2, "0123456789")
> 11

F("<('.'<)(v'.'v)(>'.'>)(^'.'^)", 31, 2, "~!@#$%^v&*()_+-=`[]{}|';:,./<>? ")
> !!~~~~~~~!!!~!~~!!!!!!!!!~~!!~!!!!!!~~!~!~!!!~!~!~!!~~!!!~!~~!!~!!~~!~!!~~!!~!~!!!~~~~!!!!!!!!!!!!~!!~!~!~~~~!~~~~!~~~~~!~~!!~~~!~!~!!!~!~~

F("~~~~~~~~~~", 31, 2, "~!@#$%^v&*()_+-=`[]{}|';:,./<>? ")
> ~

F("9876543210123456789", 10, 36, "0123456789abcdefghijklmnopqrstuvwxyz")
> 231ceddo6msr9

F("ALLYOURBASEAREBELONGTOUS", 62, 10, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
> 6173180047113843154028210391227718305282902

F("howmuchwoodcouldawoodchuckchuckifawoodchuckcouldchuckwood", 36, 95, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+=[{]}\\|;:'\",<.>/? ")
> o3K9e(r_lgal0$;?w0[`<$n~</SUk(r#9W@."0&}_2?[n

F("1100111100011010101010101011001111011010101101001111101000000001010010100101111110000010001001111100000001011000000001001101110101", 2, 95, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+=[{]}\\|;:'\",<.>/? ")
> this is much shorter
Mwr247
quelle
Wir haben eine entwickelt, um Zahlen mit willkürlicher Länge anzugehen.
Peter Taylor
@PeterTaylor Naja, irgendwie habe ich das bei meiner Suche verpasst. Trotzdem würde ich behaupten, dass sie unterschiedlich genug sind. Die andere beinhaltet einen Standardzeichensatz, Mehrbyte-Sequenzen, Fehlerbehandlung und Sequenz-zu-Sequenz-Konvertierung. All dies trägt zu einem viel größeren Aufblähen der Antworten bei und konzentriert sich auf verschiedene Optimierungen. Diese Herausforderung ist viel kürzer und führt zu einem völlig anderen Code als die andere Herausforderung (kurz vor dem Kernalgorithmus).
Mwr247,
@PeterTaylor Plus, die andere Frage wurde vor 4 Jahren gestellt und erhielt nur zwei gültige Antworten (und mit einer bereits akzeptierten, wenig Grund zu stoßen). Ich bin bereit zu wetten, dass die Community diese Herausforderung mit geringen Auswirkungen der vorherigen oder Gefühlen der "Wiederholbarkeit" genießen würde.
Mwr247
7
Obwohl diese Herausforderung der vorherigen sehr ähnlich ist, würde ich die vorherige Herausforderung lieber als Betrug schließen. Diese Herausforderung ist viel klarer und qualitativ hochwertiger als die alte.
Mego
Könnten Sie etwas näher darauf eingehen You cannot use built in change-of-base functions to convert the entire input string/number at once? Konnte ich ein eingebautes verwenden, um den Eingang in eine Zwischenbasis umzuwandeln? Kann ich dann ein eingebautes verwenden, um auf die Zielbasis zu konvertieren? Möchten Sie etwas convert input with canonical form for given base; convert to base 10; convert to target base; convert back to specified character set with string replacement?
Mego

Antworten:

5

CJam, 34 Bytes

0ll:Af#lif{@*+}~li:X;{XmdA=\}h;]W%

Das Eingabeformat steht input_N alphabet input_B output_Bjeweils in einer eigenen Zeile.

Führen Sie alle Testfälle aus.

Erläuterung

0     e# Push a zero which we'll use as a running total to build up the input number.
l     e# Read the input number.
l:A   e# Read the alphabet and store it in A.
f#    e# For each character in the input number turn it into its position in the alphabet,
      e# replacing characters with the corresponding numerical digit value.
li    e# Read input and convert to integer.
f{    e# For each digit (leaving the base on the stack)...
  @*  e#   Pull up the running total and multiply it by the base.
  +   e#   Add the current digit.
}
~     e# The result will be wrapped in an array. Unwrap it.
li:X; e# Read the output base, store it in X and discard it.
{     e# While the running total is not zero yet...
  Xmd e#   Take the running total divmod X. The modulo gives the next digit, and
      e#   the division result represents the remaining digits.
  A=  e#   Pick the corresponding character from the alphabet.
  \   e#   Swap the digit with the remaining value.
}h
;     e# We'll end up with a final zero on the stack which we don't want. Discard it.
]W%   e# Wrap everything in an array and reverse it, because we've generated the 
      e# digits from least to most significant.

Dies funktioniert für die gleiche Anzahl von Bytes:

L0ll:Af#lif{@*+}~li:X;{XmdA=@+\}h;

Der einzige Unterschied besteht darin, dass wir eine Zeichenfolge aufbauen, anstatt alles auf dem Stapel zu sammeln und umzukehren.

Martin Ender
quelle
7

Python 2 , 115 114 106 105 94 Bytes

Golfvorschläge sind willkommen. Probieren Sie es online!

Edit: -9 Bytes dank mbomb007. -2 Bytes dank FlipTack.

def a(n,f,t,d,z=0,s=''):
 for i in n:z=z*f+d.find(i)
 while z:s=d[z%t]+s;z/=t
 print s or d[0]

Ungolfed:

def arbitrary_base_conversion(num, b_from, b_to, digs, z=0, s=''):
    for i in num:
        z = z * b_from + digs.index(i)
    while z:
        s = digs[z % b_to] + s
        z = z / t
    if s:
        return s
    else:
        return d[0]
Sherlock9
quelle
1
while z:s=d[z%t]+s;z/=tspart 9 Bytes.
mbomb007
Sie könnten z=0und s=''in die Funktionsdeklaration setzen, um Bytes zu sparen.
FlipTack
Die Verwendung von printanstelle von returnist standardmäßig zulässig .
FlipTack
6

Im Ernst, 50 Bytes

0╗,╝,2┐,3┐,4┐╛`4└í╜2└*+╗`MX╜ε╗W;3└@%4└E╜@+╗3└@\WX╜

Hex Dump:

30bb2cbc2c32bf2c33bf2c34bfbe6034c0a1bd32c02a2bbb60
4d58bdeebb573b33c0402534c045bd402bbb33c0405c5758bd

Ich bin stolz auf diese trotz ihrer Länge. Warum? Weil es beim zweiten Versuch perfekt geklappt hat. Ich schrieb es und debuggte es in buchstäblich 10 Minuten. Normalerweise ist das Debuggen eines Seriously-Programms eine Stunde Arbeit.

Erläuterung:

0╗                                                  Put a zero in reg0 (build number here)
  ,╝,2┐,3┐,4┐                                       Put evaluated inputs in next four regs
             ╛                                      Load string from reg1
              `         `M                          Map over its chars
               4└                                   Load string of digits
                 í                                  Get index of char in it.
                  ╜                                 Load number-so-far from reg0
                   2└*                              Multiply by from-base
                      +                             Add current digit.
                       ╗                            Save back in reg0
                          X                         Discard emptied string/list.
                           ╜                        Load completed num from reg0
                            ε╗                      Put empty string in reg0
                              W                W    While number is positive
                               ;                    Duplicate
                                3└@%                Mod by to-base.
                                    4└E             Look up corresponding char in digits
                                       ╜@+          Prepend to string-so-far.
                                                      (Forgetting this @ was my one bug.)
                                          ╗         Put it back in reg0
                                           3└@\     integer divide by to-base.
                                                X   Discard leftover 0
                                                 ╜  Load completed string from reg0
                                                    Implicit output.
Quintopie
quelle
3

C (Funktion) mit GMP-Bibliothek , 260

Dies stellte sich länger heraus als ich gehofft hatte, aber hier ist es trotzdem. Das mpz_*Zeug frisst wirklich viele Bytes. Ich habe es versucht #define M(x) mpz_##x, aber das ergab einen Nettogewinn von 10 Bytes.

#include <gmp.h>
O(mpz_t N,int t,char*d){mpz_t Q,R;mpz_inits(Q,R,0);mpz_tdiv_qr_ui(Q,R,N,t);mpz_sgn(Q)&&O(Q,t,d);putchar(d[mpz_get_ui(R)]);}F(char*n,int f,int t,char*d){mpz_t N;mpz_init(N);while(*n)mpz_mul_ui(N,N,f),mpz_add_ui(N,N,strchr(d,*n++)-d);O(N,t,d);}

Die Funktion F() ist der Einstiegspunkt. Es konvertiert die Eingabezeichenfolge in eine mpz_tFolge von Multiplikationen mit der fromBasis und fügt den Index der angegebenen Ziffer in die Ziffernliste ein.

Die Funktion O() ist eine rekursive Ausgabefunktion. Jede Rekursion teilt die mpz_tdurch dieto -base. Da dies die ausgegebenen Ziffern in umgekehrter Reihenfolge ergibt, können die Ziffern durch die Rekursion effektiv auf dem Stapel gespeichert und in der richtigen Reihenfolge ausgegeben werden.

Testfahrer:

Zeilenumbrüche und Einrückungen zur besseren Lesbarkeit hinzugefügt.

#include <stdio.h>
#include <string.h>

#include <gmp.h>
O(mpz_t N,int t,char*d){
  mpz_t Q,R;
  mpz_inits(Q,R,0);
  mpz_tdiv_qr_ui(Q,R,N,t);
  mpz_sgn(Q)&&O(Q,t,d);
  putchar(d[mpz_get_ui(R)]);
}
F(char*n,int f,int t,char*d){
  mpz_t N;
  mpz_init(N);
  while(*n)
    mpz_mul_ui(N,N,f),mpz_add_ui(N,N,strchr(d,*n++)-d);
  O(N,t,d);
}

int main (int argc, char **argv) {
  int i;

  struct test_t {
    char *n;
    int from_base;
    int to_base;
    char *digit_list;
  } test[] = {
    {"1010101", 2, 10, "0123456789"},
    {"0001010101", 2, 10, "0123456789"},
    {"85", 10, 2, "0123456789"},
    {"1010101", 10, 2, "0123456789"},
    {"bababab", 2, 10, "abcdefghij"},
    {"10", 3, 2, "0123456789"},
    {"<('.'<)(v'.'v)(>'.'>)(^'.'^)", 31, 2, "~!@#$%^v&*()_+-=`[]{}|';:,./<>? "},
    {"~~~~~~~~~~", 31, 2, "~!@#$%^v&*()_+-=`[]{}|';:,./<>? "},
    {"9876543210123456789", 10, 36, "0123456789abcdefghijklmnopqrstuvwxyz"},
    {"ALLYOURBASEAREBELONGTOUS", 62, 10, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"},
    {"howmuchwoodcouldawoodchuckchuckifawoodchuckcouldchuckwood", 36, 95, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+=[{]}\\|;:'\",<.>/? "},
    {"1100111100011010101010101011001111011010101101001111101000000001010010100101111110000010001001111100000001011000000001001101110101", 2, 95, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+=[{]}\\|;:'\",<.>/? "},
    {0}
  };

  for (i = 0; test[i].n; i++) {
    F(test[i].n, test[i].from_base, test[i].to_base, test[i].digit_list);
    puts("");
  }

  return 0;
}
Digitales Trauma
quelle
3

JavaScript (ES6), 140 Byte

(s,f,t,m)=>[...s].map(c=>{c=m.indexOf(c);for(i=0;c||i<r.length;i++)r[i]=(n=(r[i]|0)*f+c)%t,c=n/t|0},r=[0])&&r.reverse().map(c=>m[c]).join``

Im Gegensatz zum Code von @ Mwr247 (der die Basis-f-Arithmetik verwendet, um s jedes Mal durch t zu dividieren und jeden Rest zu sammeln, während er geht) verwende ich die Basis-t-Arithmetik, um die Antwort jedes Mal mit f zu multiplizieren und dabei jede Ziffer von s zu addieren.

Ungolfed:

function base(source, from, to, mapping) {
    result = [0];
    for (j = 0; j < s.length; s++) {
        carry = mapping.indexOf(s[j]);
        for (i = 0; carry || i < result.length; i++) {
            next = (result[i] || 0) * from + carry;
            result[i] = next % to;
            carry = Math.floor(next / to);
         }
    }
    string = "";
    for (j = result.length; j --> 0; )
        string += mapping[result[j]];
    return string;
}
Neil
quelle
3

Ruby, 113 112 105 98 97 95 87 Bytes

Ich habe meine Python-Antwort (irgendwie) doppelt gepostet, also hier eine Ruby-Antwort. Sieben weitere Bytes dank manatwork , ein weiteres Byte dank Martin Büttner und 8 weitere Bytes dank cia_rana .

->n,f,t,d{z=0;s='';n.chars{|i|z=z*f+d.index(i)};(s=d[z%t]+s;z/=t)while z>0;s[0]?s:d[0]}

Ungolfed:

def a(n,f,t,d)
  z=0
  s=''
  n.chars do |i|
    z = z*f + d.index(i)
  end
  while z>0 
    s = d[z%t] + s
    z /= t
  end
  if s[0]   # if n not zero
    return s
  else
    return d[0]
  end
end
Sherlock9
quelle
Wie wäre es s=d[z%t]+s;z/=tstatt zu verwenden z,m=z.divmod t;s=d[m]+s?
Cia_rana
3

APL, 10 Bytes

{⍺⍺[⍵⍵⍳⍵]}

Dies ist ein APL-Operator. In APL werden und zum Übergeben von Werten verwendet, während ⍵⍵und ⍺⍺normalerweise zum Übergeben von Funktionen verwendet werden. Ich missbrauche dies hier, um 3 Argumente zu haben.⍺⍺ist das linke Argument, ⍵⍵ist das "innere" rechte Argument und ist das "äußere" rechte Argument.

Grundsätzlich: ⍺(⍺⍺{...}⍵⍵)⍵

Dann brauchen wir nur noch noch die Positionen der Eingabezeichenfolge in der "from" -Tabelle finden und dann []mit diesen Positionen in die "to" -Tabelle indexieren.

Beispiel:

    ('012345'{⍺⍺[⍵⍵⍳⍵]}'abcdef')'abcabc'
012012
Ven
quelle
2

JavaScript (ES6), 175 Byte

(s,f,t,h)=>eval('s=[...s].map(a=>h.indexOf(a));n=[];while(s.length){d=m=[],s.map(v=>((e=(c=v+m*f)/t|0,m=c%t),e||d.length?d.push(e):0)),s=d,n.unshift(m)}n.map(a=>h[a]).join``')

Ich dachte, es ist lange genug her, dass ich das einreichen kann, das ich gemacht habe, um die Beispiele zu erstellen. Vielleicht versuche ich es später ein bisschen besser.

Mwr247
quelle