Konversi Basis Dengan String

16

pengantar

Kami memiliki beberapa tantangan konversi basis di sini di masa lalu, tetapi tidak banyak yang dirancang untuk menangani angka panjang yang sewenang-wenang (yaitu, angka yang cukup panjang sehingga meluap datatype integer), dan dari mereka, yang paling terasa sedikit rumit. Saya ingin tahu bagaimana bisa mendapatkan perubahan kode dasar seperti ini.

Tantangan

Tulis program atau fungsi dalam bahasa pilihan Anda yang dapat mengubah string dari satu basis ke string dari basis lain. Input harus berupa angka yang akan dikonversi (string), dari-base (nomor basis-10), ke-base (nomor basis-10), dan set karakter (string). Output harus berupa angka yang dikonversi (string).

Beberapa perincian dan aturan lebih lanjut adalah sebagai berikut:

  • Angka yang akan dikonversi akan berupa bilangan bulat non-negatif (karena -dan .mungkin ada dalam rangkaian karakter). Demikian juga dengan hasilnya.
  • Memimpin nol (karakter pertama dalam rangkaian karakter) harus dipangkas. Jika hasilnya nol, satu digit nol harus tetap.
  • Kisaran dasar minimum yang didukung adalah 2 hingga 95, terdiri dari karakter ascii yang dapat dicetak.
  • Input untuk nomor yang akan dikonversi, set karakter, dan output semua harus dari tipe data string. Basis harus dari datatype integer basis-10 (atau integer float).
  • Panjang string nomor input bisa sangat besar. Sulit untuk mengukur minimum yang masuk akal, tetapi mengharapkannya mampu menangani setidaknya 1000 karakter, dan menyelesaikan input 100 karakter dalam waktu kurang dari 10 detik pada mesin yang layak (sangat murah hati untuk masalah seperti ini, tapi saya tidak ingin kecepatan menjadi fokus).
  • Anda tidak dapat menggunakan built-in fungsi perubahan basis.
  • Input set karakter dapat dalam pengaturan apa pun, bukan hanya khas 0-9a-z ... dll.
  • Asumsikan bahwa hanya input yang valid yang akan digunakan. Jangan khawatir tentang penanganan kesalahan.

Pemenang akan ditentukan oleh kode terpendek yang memenuhi kriteria. Mereka akan dipilih setidaknya dalam 7 basis-10 hari, atau jika / ketika ada cukup kiriman. Jika terjadi seri, kode yang berjalan lebih cepat akan menjadi pemenang. Jika cukup dekat dalam kecepatan / kinerja, jawaban yang datang sebelumnya menang.

Contohnya

Berikut adalah beberapa contoh input dan output yang harus dapat ditangani kode Anda:

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
sumber
Kami telah memiliki satu yang dirancang untuk menangani angka panjang sewenang-wenang.
Peter Taylor
@ PeterTaylor Ya ampun, entah bagaimana melewatkan yang dalam pencarian saya. Namun, saya berpendapat mereka cukup berbeda. Yang lainnya melibatkan set karakter default, urutan multi-byte, penanganan kesalahan, dan konversi urutan ke urutan. Semua ini menambah mengasapi jawaban yang lebih besar, dan fokus pada berbagai optimasi. Tantangan ini jauh lebih dipangkas, dan akan menghasilkan kode yang sama sekali berbeda dari tantangan lainnya (singkat dari algoritma inti).
Mwr247
@PeterTaylor Plus, pertanyaan lain ditanyakan 4 tahun lalu dan hanya menerima dua jawaban yang valid (dan dengan satu sudah diterima, sedikit alasan untuk bertemu). Saya berani bertaruh komunitas akan menikmati tantangan ini, dengan sedikit dampak dari yang sebelumnya, atau perasaan "berulang-ulang".
Mwr247
7
Meskipun tantangan ini sangat mirip dengan yang sebelumnya, saya sebenarnya lebih suka menutup yang sebelumnya sebagai penipu dari yang ini. Tantangan ini jauh lebih jelas dan kualitas lebih tinggi daripada yang lama.
Mego
Bisakah Anda sedikit menjelaskan You cannot use built in change-of-base functions to convert the entire input string/number at once? Secara khusus, dapatkah saya menggunakan built-in untuk mengkonversi input ke basis perantara? Bisakah saya menggunakan built-in untuk mengonversi ke basis target? Akankah sesuatu seperti 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

Jawaban:

5

CJam, 34 byte

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

Format input input_N alphabet input_B output_Bmasing - masing pada baris yang terpisah.

Jalankan semua test case.

Penjelasan

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.

Ini berfungsi untuk jumlah byte yang sama:

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

Satu-satunya perbedaan adalah bahwa kami membuat string alih-alih mengumpulkan semua yang ada di tumpukan dan membalikkannya.

Martin Ender
sumber
7

Python 2 , 115 114 106 105 94 byte

Saran golf diterima. Cobalah online!

Sunting: -9 bytes berkat mbomb007. -2 byte berkat 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]

Tidak Terkumpul:

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
sumber
1
while z:s=d[z%t]+s;z/=tmenghemat 9 byte.
mbomb007
Anda bisa meletakkan z=0dan s=''dalam deklarasi fungsi untuk menyimpan byte.
FlipTack
menggunakan printbukannya returnyang diizinkan secara default .
FlipTack
6

Serius, 50 byte

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

Hex Dump:

30bb2cbc2c32bf2c33bf2c34bfbe6034c0a1bd32c02a2bbb60
4d58bdeebb573b33c0402534c045bd402bbb33c0405c5758bd

Saya bangga dengan yang satu ini meskipun panjangnya. Mengapa? Karena itu bekerja dengan sempurna pada percobaan kedua. Saya menulisnya dan mendebatnya dalam 10 menit. Biasanya debugging suatu program Serius adalah satu jam kerja.

Penjelasan:

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.
kuintopia
sumber
3

C (fungsi) dengan perpustakaan GMP , 260

Ini ternyata lebih lama dari yang saya harapkan, tapi ini dia. mpz_*Barang - barang benar-benar memakan banyak byte. Saya mencoba #define M(x) mpz_##x, tetapi itu memberikan keuntungan bersih 10 byte.

#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);}

Fungsi F()adalah titik masuk. Ia mengubah string input menjadi mpz_tperkalian secara beruntun dengan from-base dan penambahan indeks dari digit yang diberikan dalam daftar digit.

Fungsi O()ini adalah fungsi keluaran rekursif. Setiap rekursi divmods mpz_toleh to-base. Karena ini menghasilkan digit output dalam urutan terbalik, rekursi secara efektif memungkinkan digit disimpan di tumpukan dan output dalam urutan yang benar.

Tes driver:

Baris baru dan indentasi ditambahkan agar mudah dibaca.

#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;
}
digital Trauma
sumber
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``

Tidak seperti kode @ Mwr247 (yang menggunakan basis-f aritmatika untuk membagi s dengan t setiap kali, mengumpulkan setiap sisa saat ia berjalan) Saya menggunakan aritmatika basis-t untuk melipatgandakan jawaban dengan f setiap kali, menambahkan setiap digit s saat aku pergi.

Tidak Terkumpul:

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
sumber
3

Ruby, 113 112 105 98 97 95 87 byte

Saya semacam memposting ganda jawaban Python saya (entah bagaimana), jadi inilah jawaban Ruby. Tujuh byte lagi berkat manatwork , satu byte lagi terima kasih kepada Martin Büttner , dan 8 byte lagi berkat 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]}

Tidak Terkumpul:

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
sumber
Bagaimana kalau digunakan s=d[z%t]+s;z/=tbukan z,m=z.divmod t;s=d[m]+s?
cia_rana
3

APL, 10 byte

{⍺⍺[⍵⍵⍳⍵]}

Ini adalah operator APL. Di APL, dan digunakan untuk meneruskan nilai, sementara ⍵⍵dan ⍺⍺biasanya digunakan untuk melewati fungsi. Saya menyalahgunakan ini di sini untuk memiliki 3 argumen.⍺⍺adalah argumen kiri, ⍵⍵adalah argumen kanan "dalam", dan merupakan argumen kanan "luar".

Pada dasarnya: ⍺(⍺⍺{...}⍵⍵)⍵

Maka semua yang diperlukan adalah menemukan posisi string input dalam tabel "dari", dan kemudian gunakan []untuk mengindeks ke tabel "ke" dengan posisi ini.

Contoh:

    ('012345'{⍺⍺[⍵⍵⍳⍵]}'abcdef')'abcabc'
012012
Yang Mulia
sumber
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``')

Saya pikir sudah cukup lama sekarang saya bisa mengirimkan yang saya buat untuk membuat contoh. Saya mungkin mencoba dan menurunkannya sedikit lebih baik nanti.

Mwr247
sumber