การแปลงฐานด้วยสตริง


16

บทนำ

เรามีความท้าทายในการแปลงฐานสองสามที่นี่ในอดีต แต่ไม่มากที่ออกแบบมาเพื่อจัดการกับความยาวโดยพลการ ซับซ้อน. ฉันอยากรู้ว่าการเปลี่ยนแปลงของรหัสฐานแบบนี้จะเป็นอย่างไร

ท้าทาย

เขียนโปรแกรมหรือฟังก์ชั่นในภาษาที่คุณเลือกซึ่งสามารถแปลงสตริงของฐานหนึ่งเป็นสตริงของฐานอื่นได้ อินพุตควรเป็นตัวเลขที่จะถูกแปลง (สตริง), จากฐาน (หมายเลขฐาน 10), เป็นฐาน (หมายเลขฐาน 10) และชุดอักขระ (สตริง) เอาต์พุตควรเป็นตัวเลขที่แปลง (สตริง)

รายละเอียดและกฎเพิ่มเติมบางประการมีดังนี้:

  • จำนวนที่จะแปลงจะเป็นจำนวนเต็มไม่เป็นลบ (ตั้งแต่-และ.อาจอยู่ในชุดอักขระ) ดังนั้นก็จะเป็นผลลัพธ์
  • เลขศูนย์นำหน้า (อักขระแรกในชุดอักขระ) ควรถูกตัดออก หากผลลัพธ์เป็นศูนย์เลขศูนย์จะยังคงอยู่
  • ช่วงฐานขั้นต่ำที่รองรับคือ 2 ถึง 95 ซึ่งประกอบด้วยอักขระ ascii ที่พิมพ์ได้
  • อินพุตสำหรับหมายเลขที่จะถูกแปลงชุดอักขระและเอาต์พุตทั้งหมดต้องเป็นประเภทข้อมูลสตริง ฐานจะต้องเป็นประเภทข้อมูลจำนวนเต็มฐาน 10 (หรือจำนวนเต็มลอย)
  • ความยาวของสตริงหมายเลขอินพุตอาจมีขนาดใหญ่มาก เป็นการยากที่จะนับจำนวนขั้นต่ำที่เหมาะสม แต่คาดว่าจะสามารถจัดการอย่างน้อย 1,000 ตัวอักษรและป้อนตัวอักษร 100 ตัวในเวลาน้อยกว่า 10 วินาทีในเครื่องที่เหมาะสม (ใจกว้างมากสำหรับปัญหาแบบนี้ แต่ฉันไม่ต้องการ ความเร็วในการโฟกัส)
  • คุณไม่สามารถใช้ฟังก์ชั่นการเปลี่ยนฐานได้
  • อินพุตชุดอักขระสามารถอยู่ในการจัดการใด ๆ ไม่ใช่แค่แบบทั่วไป 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

เรามีหนึ่งที่ออกแบบมาเพื่อจัดการกับจำนวนความยาวโดยพลการ
Peter Taylor

@PeterTaylor ตกลงแล้วอย่างใดอย่างหนึ่งที่พลาดในการค้นหาของฉัน ถึงกระนั้นฉันก็เถียงพวกเขาแตกต่างกันพอ อีกชุดหนึ่งเกี่ยวข้องกับชุดอักขระเริ่มต้นลำดับหลายไบต์การจัดการข้อผิดพลาดและการแปลงตามลำดับ สิ่งเหล่านี้ช่วยเพิ่มจำนวนคำตอบที่มากขึ้นและมุ่งเน้นไปที่การเพิ่มประสิทธิภาพที่แตกต่างกัน ความท้าทายนี้ถูกลดทอนลงไปอีกมากและจะส่งผลให้รหัสที่แตกต่างอย่างสิ้นเชิงจากความท้าทายอื่น ๆ (สั้น ๆ ของอัลกอริทึมหลัก)
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

Python 2 , 115 114 106 105 94 ไบต์

ยินดีต้อนรับคำแนะนำการเล่นกอล์ฟ ลองออนไลน์!

แก้ไข: -9 ไบต์ขอบคุณ mbomb007 -2 ไบต์ขอบคุณ 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]

1
while z:s=d[z%t]+s;z/=tบันทึก 9 ไบต์
mbomb007

คุณสามารถใส่z=0และs=''ในการประกาศฟังก์ชั่นเพื่อบันทึกไบต์
FlipTack

ใช้printแทนreturnจะได้รับอนุญาตโดยค่าเริ่มต้น
FlipTack

6

อย่างจริงจัง 50 ไบต์

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

ฐานสิบหก:

30bb2cbc2c32bf2c33bf2c34bfbe6034c0a1bd32c02a2bbb60
4d58bdeebb573b33c0402534c045bd402bbb33c0405c5758bd

ฉันภูมิใจในสิ่งนี้แม้จะมีความยาว ทำไม? เพราะมันทำงานได้อย่างสมบูรณ์แบบในการลองครั้งที่สอง ฉันเขียนมันและ debugged ภายใน 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

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_tคูณต่อเนื่องโดยfrom-base และการเพิ่มดัชนีของตัวเลขที่กำหนดในรายการหลัก

ฟังก์ชันO()นี้เป็นฟังก์ชันเอาต์พุตแบบเรียกซ้ำ การสอบถามซ้ำแต่ละครั้งจะทำการถอดรหัส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

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 (ซึ่งใช้เลขคณิตเบส - f เพื่อหาร s ในแต่ละครั้งเก็บแต่ละส่วนที่เหลือตามที่เขาไป) ฉันใช้เลขคณิตพื้นฐานเพื่อคูณคำตอบโดย f ในแต่ละครั้ง

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

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

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

วิธีการเกี่ยวกับการใช้งานs=d[z%t]+s;z/=tแทนz,m=z.divmod t;s=d[m]+s?
cia_rana

3

APL, 10 ไบต์

{⍺⍺[⍵⍵⍳⍵]}

นี่คือโอเปอเรเตอร์ APL ใน APL และถูกใช้เพื่อส่งผ่านค่าในขณะที่⍵⍵และ⍺⍺มักใช้เพื่อส่งผ่านฟังก์ชัน ฉันเหยียดหยามสิ่งนี้ที่นี่เพื่อมี 3 ข้อโต้แย้ง ⍺⍺คืออาร์กิวเมนต์ด้านซ้าย⍵⍵คืออาร์กิวเมนต์ด้านขวา "ภายใน" และเป็นอาร์กิวเมนต์ขวา "ด้านนอก"

โดยทั่วไป: ⍺(⍺⍺{...}⍵⍵)⍵

สิ่งที่จำเป็นต้องทำก็คือค้นหาตำแหน่งของสตริงอินพุตในตาราง "จาก" จากนั้นใช้[]เพื่อจัดทำดัชนีลงในตาราง "ถึง" ด้วยตำแหน่งเหล่านี้

ตัวอย่าง:

    ('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.