30
\$\begingroup\$

The powers that be want to be able to quickly convert any number they have into their own number base using any format they would like.

Input

Your program must accept 3 parameters.

  1. Number: The string number to be converted
  2. InputFormat: the base string the number is currently in
  3. OutputFormat: the base string that the number is to be converted to.

Output

Your program must convert the Number from the old number base InputFormat to the new number base OutputFormat

Examples

("1","0123456789","9876543210") = "8"
("985724","9876543210","0123456789ABCDEF") = "37C3"
("FF","0123456789ABCDEF","0123456789") = "255"
("FF","0123456789ABCDEF","01234567") = "377"
("18457184548971248772157", "0123456789","Aa0Bb1Cc2Dd3Ee4Ff5Gg6Hh7Ii8Jj9Kk,Ll.Mm[Nn]Oo@Pp#Qq}Rr{Ss-Tt+Uu=Vv_Ww!Xx%Yy*Zz") = ",sekYFg_fdXb"

Additional

The new base 77 test is not required props if it works though

  1. if your in a language where you have to convert to a number first and are locked within 32Bit you can skip it.
  2. as it's an additional test.

All examples were generated by PHP 7.2 with the bcmath extension using the following code (vars mins but code formatted). there will probably be a shorter way this is just the way I came up with for the system I needed to do this with would be nice to see if anyone could come up with a shorter version though.

PHP 7.2 (bcmath - extension) 614 bytes

<?php
function f($a, $b, $c)
{
    $d= str_split($b,1);
    $e= str_split($c,1);
    $f= str_split($a,1);
    $g=strlen($b);
    $h=strlen($c);
    $k=strlen($a);
    $r='';
    if ($c== '0123456789')
    {
        $r=0;
        for ($i = 1;$i <= $k; $i++)
            $retval = bcadd($retval, bcmul(array_search($f[$i-1], $d),bcpow($g,$k-$i)));
        return $r;
    }
    if ($b!= '0123456789')
        $l=f($a, $b, '0123456789');
    else
        $l= $a;
    if ($l<strlen($c))
        return $e[$l];
    while($l!= '0')
    {
        $r= $e[bcmod($l,$h)].$r;
        $l= bcdiv($l,$h,0);
    }
    return $r;
}

Try it Online

Scoring

This is code golf; shortest code wins. Standard loopholes apply.

\$\endgroup\$
15
  • 5
    \$\begingroup\$ @WindmillCookies By whatever characters are in the format strings. \$\endgroup\$
    – Adám
    Commented Aug 16, 2018 at 15:43
  • 6
    \$\begingroup\$ Nice first question! :-) \$\endgroup\$
    – Giuseppe
    Commented Aug 16, 2018 at 15:49
  • 2
    \$\begingroup\$ Closely related. \$\endgroup\$ Commented Aug 16, 2018 at 15:57
  • 2
    \$\begingroup\$ It may be worth adding a test case for a "unique" base -- e.g. ["zX", "tXdsyqzSDRP02", "brFNC02bc"] => "cb". (or whatever that should actually be, if that's incorrect) \$\endgroup\$
    – anon
    Commented Aug 16, 2018 at 23:01
  • 2
    \$\begingroup\$ I'd suggest a test case with more than 36 characters in the formats, to catch anyone using built-ins that only go up to base 36 \$\endgroup\$
    – Jo King
    Commented Aug 17, 2018 at 0:21

18 Answers 18

13
\$\begingroup\$

MATL, 2 bytes

Za

Try it online!
All test cases.

For the Za lord!

\$\endgroup\$
3
  • \$\begingroup\$ .......................you know, I saw that Za did base conversion but the docs on matl.suever weren't clear that it accepted the base's characters, so I didn't try it. RIP me! \$\endgroup\$
    – Giuseppe
    Commented Aug 16, 2018 at 19:13
  • \$\begingroup\$ @Giuseppe Haha, I remembered it only because it seemed like a command that's ripe for (ab)use in some clever hack or two. Ironic that my first use of it is as a straight-up builtin answer. :) \$\endgroup\$
    – Sundar R
    Commented Aug 16, 2018 at 19:29
  • 1
    \$\begingroup\$ My first thought when I saw "Za" was "lord, Harry Dresden". +1. \$\endgroup\$
    – anon
    Commented Aug 16, 2018 at 22:57
8
\$\begingroup\$

R, 124 bytes

function(n,s,t,T=L(t),N=(match(!n,!s)-1)%*%L(s)^(L(n):1-1))intToUtf8((!t)[N%/%T^rev(0:log(N,T))%%T+1])
"!"=utf8ToInt
L=nchar

Try it online!

Ugh, this was a doozy. I use the typical base conversion tricks for R, but string manipulations in R are still messy!

\$\endgroup\$
4
  • \$\begingroup\$ Unfortunately this won't work with n="0"... you should add 2 bytes doing log(N+1,T) but causing a leading zero sometimes e.g. when you convert 31 from base 10 to base 2 :( \$\endgroup\$
    – digEmAll
    Commented Aug 19, 2018 at 10:18
  • \$\begingroup\$ To avoid the "zero issue" on logarithm without leading zeros, I don't see a lot of other solutions... you could do log(N+!N,T) of course using ! with the original meaning \$\endgroup\$
    – digEmAll
    Commented Aug 19, 2018 at 10:23
  • \$\begingroup\$ @digEmAll the OP's comments are still a bit unclear, but it seems that zero need not be supported. \$\endgroup\$
    – Giuseppe
    Commented Aug 21, 2018 at 14:27
  • \$\begingroup\$ Oh well.. that's fine then :) \$\endgroup\$
    – digEmAll
    Commented Aug 21, 2018 at 14:35
7
\$\begingroup\$

APL (Dyalog Unicode), 22 bytes

Anonymous infix lambda. Takes InputFormat as left argument and OutputFormat as right argument, and prompts for Number from stdin. Assumes ⎕IO (Index Origin) to be 0, which is default on many systems.

{⍵[(≢⍵)⊥⍣¯1⊢(≢⍺)⊥⍺⍳⎕]}

Try it online!

{} "dfn"; is left argument, is right argument
(mnemonic: left and right ends of the Greek alphabet)

⍵[] index the output format with the following:

   prompt for input

  ⍺⍳ɩndices of those characters in the input format

  ()⊥ evaluate as being in the following base:

   ≢⍺ the length of the input format

   yield that (separates ¯1 from (≢⍺))

  ()⊥⍣¯1 convert to the following base:

  ≢⍺ the length of the output format

\$\endgroup\$
7
\$\begingroup\$

C (gcc), 79 + 46 = 125 bytes

char*O;l,n;g(n){n/l&&g(n/l);write(1,O+n%l,1);}

This must be compiled with the

-Df(s,i,o)=for(n=l=0;n=n*strlen(i)+index(i,s[l])-i,s[++l];);l=strlen(O=o);g(n)

flag. (Yes, this is incredibly sketchy, which is why I'm keeping my old answer below.) This defines a macro f that outputs the answer to STDOUT.

Try it online!

C (gcc), 133 131 bytes

char*O;l;g(n){n/l&&g(n/l);write(1,O+n%l,1);}f(s,i,o,n)char*s,*i,*o;{for(n=0,l=strlen(O=o);n=n*strlen(i)+index(i,*s)-i,*++s;);g(n);}

Try it online!

This defines a function f that outputs the answer to STDOUT.

char*O;           // declare variable to store output charset
l;                // will be set to length of O
g(n){             // helper function to print the result
  n/l&&g(n/l);    // recursively calls itself if there are more digits
  write(1,        // output to stdout...
   O+n%l,1);      // the byte at (n mod output base) in O
}
f(s,i,o,n)        // main function
char*s,*i,*o;{    // declare string inputs
for(n=0,          // initialize n to 0
l=strlen(O=o);    // assign output charset so we don't have to pass it to g
n=n*strlen(i)     // repeatedly multiply n by input base...
+index(i,*s)-i,   // ... add the index of the digit in input charset...
*++s;);           // and move to the next digit until there's none left
g(n);             // call the helper function on the resulting integer
}
\$\endgroup\$
2
  • \$\begingroup\$ You can save 2 bytes by using putchar instead of write and changing the decoding loop slightly: Try it online! \$\endgroup\$
    – ErikF
    Commented Aug 17, 2018 at 1:04
  • \$\begingroup\$ This index function saved me one byte as well with my approach, didn't know about it ;) \$\endgroup\$ Commented Aug 17, 2018 at 10:42
7
\$\begingroup\$

Japt, 5 3 bytes

nVW

Try it


Explanation

         :Implicit input of U=Number, V=InputFormat & W=OutputFormat
 nVW     :Convert U from base V to base W
\$\endgroup\$
6
\$\begingroup\$

05AB1E, 5 bytes

ÅβIÅв

Try it online!

This does not work in the legacy version of 05AB1E. It only works on the new version, the Elixir rewrite.

How it works

ÅβIÅв – Full program.
Åβ    – Convert from custom base to decimal.
  I   – Push the third input.
   Åв – Convert from decimal to custom base. 
\$\endgroup\$
2
  • \$\begingroup\$ You state it only works in 05AB1E v2 (not sure if that's the correct version number..), but you still provided a TIO-link. Is the Elixir version already on TIO?! :S Or it works for most test cases, but there are some edge cases where it only works in the new version? \$\endgroup\$ Commented Aug 17, 2018 at 6:48
  • 2
    \$\begingroup\$ 05AB1E v2 is now available on TIO. 05AB1E (legacy) (search it in the tio bar) is the name of the old 05AB1E and 05AB1E is the name of the new one. I know you've already seen that in the chatroom, though, but I'll leave it here as a reference for other users. \$\endgroup\$
    – Mr. Xcoder
    Commented Aug 17, 2018 at 8:17
4
\$\begingroup\$

Charcoal, 5 bytes

⍘⍘SSS

Try it online! Link is to verbose version of code. Explanation:

  S     Input the "number"
   S    Input the input format
 ⍘      Convert to number using that format
    S   Input the output format
⍘       Convert to string using that format
        Implicitly print

The BaseString function automatically converts between number and string depending on the type of the first parameter.

\$\endgroup\$
4
\$\begingroup\$

MATL, 5 bytes

sundar found the real builtin to do this! Go upvote that answer instead of my dumb one :-(

ZAwYA

Try it online!

          % implicit input N, the number, and S, the digits of the Source base
ZA        % base2dec, convert string N using S as digits into a base 10 integer
w         % swap stack elements, with implicit input T, the digits of the Target base
YA        % dec2base, reverse the ZA operation with digits coming from T instead.
\$\endgroup\$
3
\$\begingroup\$

Python 2, 132 129 122 121 bytes

lambda n,a,b:g(sum(len(a)**i*a.find(j)for i,j in enumerate(n[::-1])),b)
g=lambda n,c:c[n:n+1]or g(n/len(c),c)+c[n%len(c)]

Try it online!

An anonymous function (thanks, Erik the Outgolfer!) which converts the original number to a base 10 integer, then passes the integer and the new base string to function g(), which recursively converts to the new base. Now passes length of the OutputFormat as a parameter to g().

Updated g() for a lower bytecount. (thanks, Dennis!)

Replaced index() with find(). (thanks, Mr. Xcoder!)

Ungolfed Explanation:

def f(n, a, b):
    # reverse the string to that the least significant place is leftmost
    # Ex: 985724 -> 427589
    n = n[::-1]
    # get the value of each place, which is its index in the InputFormat, times the base to the power of the place
    # Ex: 427589, 9876543210 -> 5*10^0, 7*10^1, 2*10^2, 4*10^3, 1*10^4, 0*10^5 -> [5,70,200,4000,10000,0]
    n = [a.find(j)*len(a)**i for i,j in enumerate(n)]
    # add all of the values together to bet the value in base 10
    # Ex: (5 + 70 + 200 + 4000 + 10000 + 0) = 14275
    n = sum(n)

    # call the convert to base function
    return g(n, b)

def g(n, c):
    # string slice, which will return an empty string if n:n+1 is not in range
    # an empty string is falsey
    if c[n:n+1]:
        return c[n:n+1]
    else:
        # get current least significant digit
        rem = c[n%len(c)]
        # get the rest of the integer
        div = n/len(c)

        # get the converted string for the rest of the integer, append the calculated least significant digit
        return g(div,c)+rem
\$\endgroup\$
5
  • 1
    \$\begingroup\$ You don't need f=, anonymous functions are allowed by default. \$\endgroup\$ Commented Aug 16, 2018 at 16:39
  • \$\begingroup\$ @Erik the Outgolfer Is that allowed when the anonymous function calls another function, tho? \$\endgroup\$ Commented Aug 16, 2018 at 16:43
  • \$\begingroup\$ As long as you include the other stuff in your bytecount, yes, you're allowed to define variables and import modules. \$\endgroup\$ Commented Aug 16, 2018 at 16:44
  • 1
    \$\begingroup\$ The helper function can become g=lambda n,c:c[n:n+1]or g(n/len(c),c)+c[n%len(c)]. \$\endgroup\$
    – Dennis
    Commented Aug 16, 2018 at 16:56
  • 1
    \$\begingroup\$ And the main one can become lambda n,a,b:g(sum(len(a)**i*a.find(j)for i,j in enumerate(n[::-1])),b,len(b)). \$\endgroup\$
    – Mr. Xcoder
    Commented Aug 16, 2018 at 17:10
3
\$\begingroup\$

VBA, 182 bytes

A declared subroutine which takes input, n, in the language y and projects that into language z.

Sub f(n,y,z)
l=Len(n)
For i=-l To-1
v=v+(InStr(1,y,Mid(n,-i,1))-1)*Len(y)^(l+i)
Next
l=Len(z)
While v
v=v-1
d=v Mod l+1
v=v\l
If d<0Then v=v+1:d=d-l
o=Mid(z,d+1,1)&o
Wend
n=o
End Sub
\$\endgroup\$
2
\$\begingroup\$

Jelly, 11 bytes

iⱮ’ḅL{ṃ⁵ṙ1¤

Try it online!

Argument order: InputFormat, Number, OutputFormat. Be sure to quote the arguments with proper escaping!

\$\endgroup\$
4
  • \$\begingroup\$ Hrm not sure I did explicitly state the order of the params... \$\endgroup\$ Commented Aug 16, 2018 at 16:10
  • \$\begingroup\$ @MartinBarker The params are taken in order 2, 1, 3 here. I can't see a requirement for a specific order in the challenge, and that would be discouraged. \$\endgroup\$ Commented Aug 16, 2018 at 16:12
  • 3
    \$\begingroup\$ @MartinBarker Pro Tip: Be flexible with such things. I find the order of the inputs to be completely irrelevant when solving a task, so I suggest that you allow any arbitrarily chosen ordering of the parameters \$\endgroup\$
    – Mr. Xcoder
    Commented Aug 16, 2018 at 16:13
  • \$\begingroup\$ i was gonna let it stick anyways just trying to test it now. \$\endgroup\$ Commented Aug 16, 2018 at 16:14
2
\$\begingroup\$

Pyth, 21 bytes

s@LeQjimx@Q1dhQl@Q1le

Test suite

Explanation:
s@LeQjimx@Q1dhQl@Q1le  | Code
s@LeQjimx@Q1dhQl@Q1leQ |  with implicit variables
       m               | Map the function
        x   d          |   index of d in
         @Q1           |    the second string in the input
             hQ        |  over the first string in the input
      i                | Convert the resulting list to int from base
               l@Q1    |  length of the second string in the input
     j                 | Convert the int into a list in base
                   leQ |  length of the last string in the input
 @LeQ                  | Turn each number in the list into the character from the numbers index in the last string in the input
s                      | Concatenate the strings in to one string
                       | Implicit print
\$\endgroup\$
2
\$\begingroup\$

Haskell, 119 bytes

n!f=init.((foldl((+).(l f*))0[i|c<-n,(i,d)<-zip[0..]f,d==c],0)#)
(0,d)#b=[b!!d]
(r,d)#b=r`divMod`l b#b++[b!!d]
l=length

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Perl 6, 100 97 bytes

{$^c.comb[(":"~$^b.chars~[$^a.comb>>.&{index $b,$_}].perl).EVAL.polymod($c.chars xx*)].join.flip}

Try it online!

Anonymous code block that takes 3 strings in order, input, input format and output format, then returns a string

Explanation:

{  # Anonymous code block
  $^c.comb[  # Split the output format into characters
           (":"~$^b.chars~[$^a.comb>>.&{index $b,$_}].perl) # The radix syntax in a string e.g ":3[1,2,3]"
           .EVAL  # Eval'ed to produce the base 10 version
           .polymod($c.chars xx*)  # Converted to a list in the output base (reversed)
          ] # Convert the list into indexes of the output format
           .join  # Join the characters to a string
           .flip  # And unreversed
}
\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 90 86 bytes

Takes input as (input_format)(output_format)(number).

s=>d=>g=([c,...n],k=0)=>c?g(n,k*s.length+s.search(c)):k?g(n,k/(l=d.length)|0)+d[k%l]:n

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ Sorry, this is not valid as your changing the input format of the string to an array that is not something that can be done via a CLI input. and has to be programmed you need split the string into the array for the first param for this to be valid. \$\endgroup\$ Commented Aug 20, 2018 at 22:36
  • \$\begingroup\$ @MartinBarker Which rule are you referring to? Updated to take 3 strings anyway. \$\endgroup\$
    – Arnauld
    Commented Aug 21, 2018 at 4:26
  • \$\begingroup\$ All 3 of the input parameters says "string" as C++ a string can be directly read in and used as an array with javascript it can't be. \$\endgroup\$ Commented Aug 21, 2018 at 17:42
1
\$\begingroup\$

C (gcc), 130 129 bytes

v;c(r,i,s,t)char*r,*i,*t;{for(r[1]=v=0;*i;v=v*strlen(s)+index(s,*i++)-s);for(s=strlen(t),i=1;*r=t[v%s],v/=s;memmove(r+1,r,++i));}

Try it online!

-1 byte using index instead of strchr.

This is a simple iterative approach, reusing some variables (and thereby abusing sizeof(int) == sizeof(char *) on TIO) to save bytes.

Input:

  • i input number
  • s source base characters
  • t target base characters

Output:

  • r result number (pointer to a buffer)

Explanation:

v;                                        // value of number
c(r,i,s,t)char*r,*i,*t;{
    for(r[1]=v=0;                         // initialize value and second
                                          // character of output to 0
        *i;                               // loop while not at the end of
                                          // input string
         v=v*strlen(s)+index(s,*i++)-s);  // multiply value with source base
                                          // and add the value of the current
                                          // digit (position in the base string)
    for(s=strlen(t),i=1;                  // initialize s to the length of the
                                          // target base string, length of
                                          // result to 1
        *r=t[v%s],v/=s;                   // add character for current digit
                                          // (value modulo target base) and
                                          // divide value by target base until
                                          // 0 is reached
        memmove(r+1,r,++i));              // move result string one place to
                                          // the right
}
\$\endgroup\$
1
  • \$\begingroup\$ Suggest bcopy(r,r+1,++i) instead of memmove(r+1,r,++i) \$\endgroup\$
    – ceilingcat
    Commented Aug 21, 2018 at 19:14
1
\$\begingroup\$

Python 2, 97 95 bytes

Thanks to Chas Brown for -2 bytes.

n,s,t=input()
k=0;w='';x=len(t)
for d in n:k=len(s)*k+s.find(d)
while k:w=t[k%x]+w;k/=x
print w

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

Java 10, 131 bytes

A lambda taking the parameters in order as strings and returning a string.

(i,f,o)->{int n=0,b=o.length();var r="";for(var c:i.split(r))n=n*f.length()+f.indexOf(c);for(;n>0;n/=b)r=o.charAt(n%b)+r;return r;}

Try It Online

Ungolfed

(i, f, o) -> {
    int n = 0, b = o.length();
    var r = "";
    for (var c : i.split(r))
        n = n * f.length() + f.indexOf(c);
    for (; n > 0; n /= b)
        r = o.charAt(n % b) + r;
    return r;
}
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.