문자열을 사용한 기본 변환


16

소개

과거에는 몇 가지 기본 변환 문제가 있었지만 임의 길이의 숫자 (즉, 정수 데이터 유형을 오버플로하기에 충분히 긴 숫자)를 다루기 위해 설계된 것은 많지 않았습니다. 복잡한. 이와 같은 기본 코드 변경을 어떻게 해결할 수 있는지 궁금합니다.

도전

한베이스의 문자열을 다른베이스의 문자열로 변환 할 수있는 프로그램 또는 함수를 선택한 언어로 작성하십시오. 입력 할 수는 변환 할 숫자 (문자열), 기본 (기본 10 숫자), 기본 (기본 10 숫자) 및 문자 집합 (문자열)이어야합니다. 출력은 변환 된 숫자 (문자열) 여야합니다.

추가 세부 사항 및 규칙은 다음과 같습니다.

  • 수는 음이 아닌 정수 것이다 변환한다 (사람 -.문자 세트 일 수있다). 출력도 마찬가지입니다.
  • 선행 0 (문자 세트의 첫 번째 문자)은 다듬어야합니다. 결과가 0이면 하나의 0 자리 숫자가 남아 있어야합니다.
  • 지원되는 최소 기본 범위는 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

우리 임의의 길이의 숫자를 다루기 위해 고안되었습니다.
피터 테일러

@PeterTaylor Well dang, 어떻게 든 내 검색에서 그 것을 놓쳤습니다. 아직도, 나는 그들이 충분히 다르다고 주장합니다. 다른 하나는 기본 문자 세트, 멀티 바이트 시퀀스, 오류 처리 및 시퀀스에서 시퀀스로의 변환입니다. 이 모든 것이 답변에서 훨씬 더 큰 부풀어 오르고 다른 최적화에 중점을 둡니다. 이 도전은 훨씬 더 잘려나 가고 다른 도전과는 완전히 다른 코드 (핵심 알고리즘의 부족)를 초래합니다.
Mwr247

@PeterTaylor Plus, 다른 질문은 4 년 전에 요청되었으며 두 가지 유효한 답변 만 받았습니다 (하나는 이미 받아 들였지만 충돌 할 이유가 거의 없었습니다). 나는 공동체가 이전 도전과 거의 같은 영향을 미치거나 "반복성"이라는 느낌으로이 도전을 누리게 될 것이라고 확신합니다.
Mwr247

7
이 과제는 이전 과제와 매우 유사하지만 실제로는 이전 과제를 속임수로 사용하는 것이 좋습니다. 이 도전은 이전 도전보다 훨씬 명확하고 높은 품질입니다.
Mego

좀 더 자세히 설명해 주 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입니까?
Mego

답변:


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

파이썬 (2) , 115 (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

나는 길이에도 불구 하고이 것을 자랑스럽게 생각합니다. 왜? 두 번째 시도에서 완벽하게 작동했기 때문입니다. 나는 그것을 작성하고 문자 그대로 10 분 안에 디버깅했습니다. 보통 심각하게 프로그램을 디버깅하는 것은 한 시간의 노동입니다.

설명:

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

GMP 라이브러리가있는 C (기능) , 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()은 진입 점입니다. -base에 mpz_t의한 연속 곱셈 from과 숫자 목록에서 주어진 숫자의 색인을 추가 하여 입력 문자열을로 변환합니다 .

이 기능 O()은 재귀 출력 기능입니다. 각 재귀는을 divmods mpz_t에 의해 to-base. 이렇게하면 출력 자릿수가 역순으로 생성되므로 재귀를 사용하면 효과적으로 자릿수가 스택에 저장되고 올바른 순서로 출력됩니다.

테스트 드라이버 :

가독성을 위해 줄 바꿈과 들여 쓰기가 추가되었습니다.

#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

자바 스크립트 (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 바이트

나는 파이썬 답변을 두 번 게시 했으므로 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

자바 스크립트 (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.