文字列を使用したベース変換


16

前書き

過去にいくつかの基本変換の課題がありましたが、任意の長さの数値(つまり、整数データ型をオーバーフローさせるほど長い数値)に取り組むように設計されたものは多くありませんでした。複雑です。このように基本コードの変更をどのように実行できるか興味があります。

チャレンジ

あるベースの文字列を別のベースの文字列に変換できるプログラムまたは関数を選択した言語で記述します。入力は、変換される数値(文字列)、from-base(10進数)、to-base(10進数)、および文字セット(string)である必要があります。出力は、変換された数値(文字列)でなければなりません。

いくつかの詳細と規則は次のとおりです。

  • 変換される数値は負でない整数になり(以降-.文字セットであってもよいです)。出力も同様です。
  • 先行ゼロ(文字セットの最初の文字)は削除する必要があります。結果がゼロの場合、単一のゼロ桁が残るはずです。
  • サポートされる最小ベース範囲は2〜95で、印刷可能なASCII文字で構成されます。
  • 変換する数値の入力、文字セット、および出力は、すべて文字列データ型である必要があります。基数は、基数10の整数データ型(または整数浮動小数点数)でなければなりません。
  • 入力数値文字列の長さは非常に長くなる場合があります。賢明な最小値を定量化することは困難ですが、少なくとも1000文字を処理し、まともなマシンで10秒未満で100文字の入力を完了することができると期待しています(この種の問題には非常に寛大ですが、私はしたくない焦点となる速度)。
  • 組み込みの基本変更機能は使用できません。
  • 文字セットの入力は、通常の0-9a-z ...などだけでなく、任意の配置にすることができます。
  • 有効な入力のみが使用されると仮定します。エラー処理を心配しないでください。

勝者は、基準を達成する最短のコードによって決定されます。少なくとも7から10日以内に、または十分な提出があった場合は、それらが選択されます。同点の場合、より高速に実行されるコードが勝者になります。速度/パフォーマンスが十分に近い場合、先に出された答えが勝ちです。

コードで処理できる入力と出力の例を次に示します。

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

私たちはしている任意の長さの番号に取り組むために設計された1つを持っていました。
ピーターテイラー

@PeterTaylorまあ、私の検索でそれを何とか見逃しました。それでも、私は彼らが十分に異なると主張します。もう1つは、デフォルトの文字セット、マルチバイトシーケンス、エラー処理、およびシーケンスからシーケンスへの変換です。これらはすべて、答えを大きく膨らませ、さまざまな最適化に焦点を当てています。この課題は、はるかに削減されており、他の課題とはまったく異なるコードになります(コアアルゴリズムの不足)。
Mwr247

@PeterTaylor Plus、もう1つの質問は4年前に尋ねられたもので、有効な回答は2つしかありませんでした(1つはすでに受け入れられていて、ほとんど理由はありません)。私は、コミュニティが以前のチャレンジや「反復性」の感覚からほとんど影響を与えずに、このチャレンジを楽しんでくれると確信しています。
Mwr247

7
この課題は以前の課題と非常に似ていますが、実際には、この課題のduとして以前の課題を閉じることに賛成です。この課題は、古い課題よりも明確で高品質です。
メゴ

少し詳しく説明していただけますYou cannot use built in change-of-base functions to convert the entire input string/number at onceか?具体的には、組み込みを使用して入力を中間ベースに変換できますか?その後、組み込みを使用してターゲットベースに変換できますか?何かしたい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ですか?
メゴ

回答:


5

CJam、34バイト

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

入力形式はinput_N alphabet input_B output_Bそれぞれ別々の行にあります。

すべてのテストケースを実行します。

説明

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.

これは同じバイト数で機能します:

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

唯一の違いは、スタック上のすべてを収集して反転するのではなく、文字列を作成することです。


7

パイソン2115の 114 106 105 94バイト

ゴルフの提案を歓迎します。オンラインでお試しください!

編集: mbomb007のおかげで-9バイト。FlipTackのおかげで-2バイト。

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]

ゴルフをしていない:

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]

1
while z:s=d[z%t]+s;z/=t9バイト節約します。
mbomb007

関数の宣言にを入れz=0s=''、バイトを節約できます。
FlipTack

print代わりの使用returnデフォルト許可されています
FlipTack

6

真剣に、50バイト

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

六角ダンプ:

30bb2cbc2c32bf2c33bf2c34bfbe6034c0a1bd32c02a2bbb60
4d58bdeebb573b33c0402534c045bd402bbb33c0405c5758bd

私はこの長さにもかかわらず、これを誇りに思っています。どうして?2回目の試行で完全に機能したためです。私はそれを書いて、文字通り10分でデバッグしました。通常、真剣にプログラムをデバッグするには1時間かかります。

説明:

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.

3

C(関数)とGMPライブラリ、260

これは私が期待していたよりも長いことが判明しましたが、とにかくここにあります。mpz_*ものは本当にバイトをたくさん食べます。私は試しましたが#define M(x) mpz_##x、それは10バイトの純利益を与えました。

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

関数F()はエントリポイントです。入力文字列をmpz_tfrom-base による連続的な乗算と、数字リスト内の指定された数字のインデックスの追加によって、に変換します。

この関数O()は、再帰的な出力関数です。各再帰mpz_tto-baseでdivmodsします。これにより出力桁が逆の順序で出力されるため、再帰により、桁がスタックに格納され、正しい順序で出力されます。

テストドライバー:

読みやすくするために、改行とインデントが追加されました。

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

3

JavaScript(ES6)、140バイト

(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``

@ Mwr247のコード(base-f算術を使用してsを毎回tで除算し、各剰余を収集する)とは異なり、私はbase-t算術を使用して毎回fを掛け、sの各桁を加算します。

ゴルフをしていない:

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

3

ルビー、113 112 105 98 97 95 87バイト

Pythonの答えを(なんとかして)二重投稿したので、ここにRubyの答えがあります。セブンよりのおかげバイトmanatwork、に別のバイトのおかげマーティンBüttner、および8は、より多くのおかげバイト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]}

ゴルフをしていない:

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

s=d[z%t]+s;z/=t代わりに使用してはz,m=z.divmod t;s=d[m]+sどうですか?
cia_rana

3

APL、10バイト

{⍺⍺[⍵⍵⍳⍵]}

これはAPL演算子です。APLでは、およびは値を渡すために使用されますが、⍵⍵および⍺⍺は通常関数を渡すために使用されます。私はここでこれを悪用して3つの議論をしています。⍺⍺は左引数、⍵⍵「内部」右引数、および「外部」右引数です。

基本的に: ⍺(⍺⍺{...}⍵⍵)⍵

その後、必要なのは、「from」テーブルで入力文字列の位置を見つけて、[]これらの位置を使用して「to」テーブルにインデックスを付けることです。

例:

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

2

JavaScript(ES6)、175バイト

(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``')

サンプルを作成するために作成したものを提出できるようになりました。あとでゴルフを少し良くしようと思うかもしれません。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.