ตัวแปลง Unicode UTF


17

เป้าหมายคือการสร้างแปลงอย่างสอดคล้องระหว่างการเข้ารหัส Unicode อย่างเป็นทางการตามที่กำหนดในUTF คำถามที่พบบ่อย ระบุว่าสิ่งนี้มีศูนย์กลางอยู่ที่ Unicode ฉันจะยอมรับคำตอบด้วยจำนวนไบต์ต่ำสุดโดยใช้การเข้ารหัสที่ดีที่สุดเท่าที่จะเป็นไปได้ (ซึ่งอาจเป็น UTF-8 เว้นแต่คุณจะตั้งโปรแกรมใน APL) ฉันขอโทษสำหรับการโพสต์นาน แต่มากของมันจะอธิบายการเข้ารหัสซึ่งยังสามารถเข้าถึงได้ในสเปคอย่างเป็นทางการ (PDF ส่วน 3.9 D90 - D92)หรือวิกิพีเดีย

ข้อมูลจำเพาะ

หากตลอดเวลาที่คุณเลือกภาษาไม่สามารถตอบสนองความต้องการอย่างแน่นอนให้แทนที่ด้วยสิ่งที่ยึดจิตวิญญาณของกฎที่กำหนด เช่น. ไม่ใช่ทุกภาษาที่มีอาเรย์ในตัวฟังก์ชั่นและอื่น ๆ

  • ไม่ใช้ไลบรารีสตริง / ฟังก์ชันหรือเข้ารหัสไลบรารี / ฟังก์ชัน จุดประสงค์ของ code golf นี้คือการใช้เครื่องมือแปลงโดยใช้การจัดการบิต / ไบต์ การใช้สตริงเองในฐานะอักขระหรืออาร์เรย์ไบต์ได้รับอนุญาต โอ้และไม่มีการเรียกใช้ระบบปฏิบัติการที่ดำเนินการแปลงอย่างใดอย่างหนึ่ง

  • ตัวแปลงเป็นฟังก์ชั่นที่จะใช้พารามิเตอร์สามตัว: อาร์เรย์ไบต์ที่เป็นตัวแทนของสตริงอินพุตที่เข้ารหัสและการเข้ารหัส "อินพุต" และ "เอาต์พุต" ที่แสดงเป็นตัวเลข เราจะกำหนดUTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, and UTF32LEหมายเลขจาก 0 ถึง 6 ตามลำดับโดยพลการ ไม่จำเป็นต้องตรวจสอบว่าเป็นหมายเลข< 0หรือ> 6เราจะถือว่าพารามิเตอร์เหล่านี้ถูกต้อง ตัวแปลงจะส่งกลับอาร์เรย์ไบต์ที่ถูกต้องในการเข้ารหัสเอาต์พุตที่ต้องการ

  • เราจะใช้อักขระ null ( U+0000) เป็นตัวยุติสตริง หลังจากนี้สิ่งใดไม่สำคัญ เราจะสมมติว่าอาร์เรย์อินพุตมีอักขระ null อยู่ที่ไหนสักแห่งดังนั้นคุณไม่จำเป็นต้องทำการตรวจสอบขอบเขต

  • ตามคำถามที่พบบ่อยหากอาร์เรย์ไบต์อินพุตไม่ถูกต้องสำหรับการเข้ารหัสที่ประกาศไว้เราจะต้องส่งสัญญาณข้อผิดพลาด เราจะทำสิ่งนี้ด้วยวิธีใดวิธีหนึ่งต่อไปนี้: พังโปรแกรมโยนข้อยกเว้นส่งคืนค่าว่างหรือคืนอาเรย์ที่มีสี่ไบต์แรกเป็น 0 ทั้งหมด (เพื่อให้สามารถจดจำได้เช่นเดียวกับการU+0000เข้ารหัสทุกครั้ง)

การเข้ารหัส

ต้องทำตามข้อกำหนดอย่างเป็นทางการ แต่วิกิพีเดียมีคำอธิบายที่ดี (และเท่าที่ฉันเชื่อว่าถูกต้อง) เกี่ยวกับการเข้ารหัสและฉันจะสรุปให้ครบถ้วน โปรดทราบว่า UTF-16 และ UTF-32 มีตัวแปรสำหรับendianness endianness

UTF-32, UTF-32LE, UTF-32BE

การเข้ารหัสที่ง่ายที่สุดแต่ละจุดของรหัสจะถูกเข้ารหัสใน 4 ไบต์เท่ากับค่าตัวเลข LE / BE หมายถึง endianness (endian น้อย / endian ใหญ่)

UTF-16, UTF-16LE, UTF-16BE

จุดโค้ดจากU+0000 - U+FFFFนั้นจะถูกเข้ารหัสใน 2 ไบต์เท่ากับค่าตัวเลข ค่าขนาดใหญ่จะถูกเข้ารหัสโดยใช้คู่อุ้มท้องU+D800 - U+DFFFซึ่งเป็นค่าที่สงวนไว้จาก ดังนั้นเพื่อเข้ารหัสจุดที่สูงกว่าU+FFFFสามารถใช้อัลกอริทึมต่อไปนี้ได้ (คัดลอกมาจากWikipedia ):

  • 0x010000 ถูกลบออกจากจุดโค้ดโดยปล่อยตัวเลข 20 บิตในช่วง 0..0x0FFFFF
  • สิบบิตแรกสุด (ตัวเลขในช่วง 0..0x03FF) จะถูกเพิ่มเป็น 0xD800 เพื่อให้หน่วยรหัสแรกหรือตัวแทนสำรองซึ่งจะอยู่ในช่วง 0xD800..0xDBFF [... ]
  • สิบบิตต่ำ (ในช่วง 0..0x03FF) จะถูกเพิ่มใน 0xDC00 เพื่อให้หน่วยรหัสที่สองหรือตัวแทนสำรองซึ่งจะอยู่ในช่วง 0xDC00..0xDFFF [... ]

UTF-8

จุดโค้ดจากU+0000 - U+007Fนั้นถูกเข้ารหัสเป็น 1 ไบต์เท่ากับค่าตัวเลข จากการU+0080 - U+07FFที่พวกเขาจะถูกเข้ารหัส110xxxxx 10xxxxxx, U+0800 - U+FFFFเป็นค่าที่สูงขึ้น1110xxxx 10xxxxxx 10xxxxxx 11110xxx 10xxxxxx 10xxxxxx 10xxxxxxx's บิตจากค่าตัวเลขของจุดรหัส

BOM

เครื่องหมายคำสั่งแบบไบท์ (BOM, U+FEFF) ถูกใช้เป็นจุดรหัสแรกเพื่อบ่งบอกถึง endianness ต่อไปนี้แนวทางคำถามที่พบบ่อยเกี่ยวกับ BOMs , BOM จะใช้ดังนี้สำหรับUTF-8, UTF-16 and UTF-32มันเป็นตัวเลือก หาก BOM ไม่อยู่ในUTF-16หรือUTF-32ถือว่าเป็น Endian ที่ยิ่งใหญ่ รายการวัสดุจะต้องไม่UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BEปรากฏใน

ข้อผิดพลาดทั่วไปที่ทำให้ UTF ไม่ถูกต้อง

สิ่งต่าง ๆ อาจทำให้ลำดับไบต์เป็น UTF ที่ไม่ถูกต้อง

  • UTF-8 และ UTF-32:โดยตรงเข้ารหัสจุดรหัสตัวแทน ( U+D800 - U+DFFF) U+10FFFFหรือรหัสจุดมากกว่า
  • UTF-8:ลำดับไบต์ที่ไม่ถูกต้องจำนวนมาก
  • UTF-16:ตัวแทนอุ้มท้องหรือคู่ที่ไม่ถูกต้อง
  • BOM:ต้องใช้ตามที่ระบุไว้ในส่วนการเข้ารหัส โปรดทราบว่าเมื่อมีการแสดงผลUTF-16หรือUTF-32(ไม่มีการระบุความเอนเอียงโดยธรรมชาติ) คุณสามารถเลือกได้ แต่ด้วย endian เพียงเล็กน้อยคุณต้องรวม BOM

โปรดทราบว่าจุดที่ไม่ใช่ตัวอักษรและรหัสที่ไม่ได้กำหนด (ทั้งแตกต่างจากตัวแทน) จะได้รับการปฏิบัติเหมือนตัวละครปกติ


"ไม่ใช้ไลบรารีสตริง / ฟังก์ชั่นหรือเข้ารหัสไลบรารี / ฟังก์ชั่น" สิ่งที่เกี่ยวกับตัวจริง ใน ''⎕R''⍠'InEnc' 'UTF16BE' 'OutEnc' 'UTF8-BOM'APL,
อดัม

2
@NBZ สิ่งเหล่านั้นจะไม่ได้รับอนุญาตเนื่องจากประเด็นของความท้าทายนี้คือการใช้พฤติกรรมที่มีให้
DPenner1

หมายเหตุถึงผู้ตอบ: ฉันได้ละทิ้งคำถามนี้มากหรือน้อย แต่ได้รับความสนใจเมื่อเร็ว ๆ นี้ในไม่กี่วันข้างหน้าฉันจะใช้เวลาสักครู่ในการตอบคำถาม
DPenner1

คำตอบ:


3

C ++, (UTF-8) 971 ไบต์

#include<cstdint>
using u=uint8_t;using U=uint32_t;U i,o,x,b,m;U R(u*&p){x=*p++;if(!i){m=0;while(128>>m&x)++m;if(m>1)for(x&=127>>m;--m;)x=x<<6|((*p&192)-128?~0:*p++&63);return m?x=~0:x;}else if(i<3){x<<=8;x+=*p++;}else if(i<4){x+=*p++<<8;}else if(i<6){x<<=24;x+=*p++<<16;x+=*p++<<8;x+=*p++;}else{x+=*p++<<8;x+=*p++<<16;x+=*p++<<24;}return x;}U r(u*&p){U x0=R(p);if(i&&i<4&&x>>10==54)x=R(p)>>10==55?(x0<<10)+x-56613888:~0;if(!b++){if(x==65279)if(!i||i%3==1)r(p);else x=~0;else if(x==65534&&i==1)i=3,r(p);else if(x==4294836224&&i==4)i=6,r(p);}return x>1114111||x>>11==27?x=~0:x;}void w(U x,u*&p){if(!o){if(x<128)*p++=x;else{for(m=0;~63<<m&x;m+=6);for(*p++=~127>>m/6|x>>m;m;)*p++=128|x>>(m-=6)&63;}}else if(o<4&&x>65535)x-=65536,w(55296|x>>10,p),w(56320|x&1023,p);else if(o<3)*p++=x>>8,*p++=x;else if(o<4)*p++=x,*p++=x>>8;else if(o<6)*p++=x>>24,*p++=x>>16,*p++=x>>8,*p++=x;else*p++=x,*p++=x>>8,*p++=x>>16,*p++=x>>24;}int t(u*&p,u*&q){for(b=0,x=1;U(x+x);)w(r(p),q);return x;}

โปรแกรมที่อ่านได้ด้านล่างนี้สามารถย่อไปยังแบบฟอร์มด้านบนโดยการกรองผ่านคำสั่ง Perl ต่อไปนี้:

perl -p0 -e 's!//.*!!g;s/\s+/ /g;s/ \B|\B //g;s/0x[\da-f]+/hex($&)/ige;s/#include<[^<>]+>/\n$&\n/g;s/^\n+//mg'

คำสั่งดังกล่าว

  • ลบความคิดเห็น
  • ลบช่องว่างที่ไม่จำเป็น
  • แปลงตัวเลขฐานสิบหกเป็นทศนิยม
  • เรียกคืนบรรทัดใหม่รอบ ๆ#includeบรรทัด

รหัสที่อ่านได้

#include <cstdint>
using u = uint8_t;
using U = uint32_t;

U   i,                          // input encoding
    o,                          // output encoding
    x,                          // last read value
    b,                          // char count(BOM only valid when b==0)
    m;                          // temporary variable for measuring UTF-8

//   Encodings:
// 0 UTF-8
// 1 UTF-16
// 2 UTF-16BE
// 3 UTF-16LE
// 4 UTF-32
// 5 UTF-32BE
// 6 UTF-32LE

// Read a character or UTF-16 surrogate
U R(u*& p) {
    x = *p++;
    if (!i) { // UTF-8
        m=0; while (128>>m&x) ++m; // how many bytes?
        if (m>1) for (x&=127>>m; --m; ) x = x<<6 | ((*p&192)-128?~0:*p++&63);
        return m ? x=~0 : x;
    } else if (i<3) { // UTF-16, UTF-16BE
        x<<=8; x+=*p++;
    } else if (i<4) { // UTF-16LE
        x+=*p++<<8;
    } else if (i<6) { // UTF-32, UTF-32BE
        x<<=24; x+=*p++<<16; x+=*p++<<8; x+=*p++;
    } else { // UTF-32LE
        x+=*p++<<8; x+=*p++<<16; x+=*p++<<24;
    }
    return x;
}

// Read a character, combining surrogates, processing BOM, and checking range
U r(u*& p) {
    U x0 = R(p);
    if (i && i<4 && x>>10==54)
        x = R(p)>>10==55 ? (x0<<10)+x-56613888: ~0; // 56613888 == 0xd800<<10 + 0xdc00 - 0x10000
    if (!b++) {                 // first char - is it BOM?
        if (x==0xFEFF)
            if (!i || i%3==1)
                r(p); // BOM in UTF-8 or UTF-16 or UTF-32 - ignore, and read next char
            else
                x = ~0; // not allowed in these modes
        else if (x==0xFFFE && i==1)
            i=3,r(p); // reversed BOM in UTF-16 - change to little-endian, and read next char
        else if (x==0xFFFE0000 && i==4)
            i=6,r(p); // reversed BOM in UTF-32 - change to little-endian, and read next char
    }
    return x>0x10ffff || x>>11==27 ? x=~0 : x;
}


// Write character(assumed in-range)
void w(U x, u*& p) {
    if (!o) { // UTF-8
        if (x<128) *p++=x;        // ASCII
        else {
            for (m=0; ~63<<m&x; m+=6); // how many bits?
            for (*p++=~127>>m/6|x>>m; m; ) *p++ = 128|x>>(m-=6)&63;
        }
    } else if (o<4 && x>65535)  // UTF-16 surrogate
        x-=65536, w(0xD800|x>>10,p), w(0xDC00|x&0x3FF,p);
    else if (o<3)  // UTF-16, UTF-16BE
        *p++=x>>8, *p++=x;
    else if (o<4)  // UTF-16LE
        *p++=x, *p++=x>>8;
    else if (o<6)  // UTF-32, UTF-32BE
        *p++=x>>24, *p++=x>>16, *p++=x>>8, *p++=x;
    else  // UTF-32LE
        *p++=x, *p++=x>>8, *p++=x>>16, *p++=x>>24;
}

// Transcode
int t(u*& p, u*& q)                  // input, output
{
    for (b=0,x=1;U(x+x);)    // exit condition is true only for x==-x, i.e. 0 and ~0
        w(r(p),q);
    return x;
}

ฟังก์ชั่นที่จะเรียกใช้คือt()มีการเข้ารหัสอินพุตและเอาต์พุตที่ส่งผ่านในตัวแปรโกลบอลiและoตามลำดับและpชี้ไปที่ไบต์ของอินพุตซึ่งจะต้องสิ้นสุดด้วยค่า null qชี้ไปที่บัฟเฟอร์เอาต์พุตซึ่งจะถูกเขียนทับและต้องมีขนาดใหญ่พอสำหรับผลลัพธ์ - ไม่มีความพยายามที่จะหลีกเลี่ยงบัฟเฟอร์ที่โอเวอร์รัน

ฉันหวังว่าความคิดเห็นของรหัสจะอธิบายอย่างเพียงพอ - ถามด้านล่างว่าหนึ่งในนั้นเป็นความลับเกินไป (แต่พยายามก่อน!)

ฉันรวบรวมชุดการทดสอบที่สำคัญขณะที่พัฒนาคำตอบนี้ ฉันรวมไว้ด้านล่างเพื่อประโยชน์ของผู้เข้าร่วมรายอื่นและเพื่อจัดทำเอกสารการตีความข้อกำหนดของฉัน:

ฟังก์ชั่นทดสอบ

#include <vector>
#include <iostream>

std::ostream& operator<<(std::ostream& out, const std::vector<u>& v)
{
    out << "{ ";
    for (int i: v) out << i << " ";
    out << "}";
    return out;
}

int test_read(int encoding, std::vector<u> input, U expected)
{
    b = 0;
    i = encoding;
    auto d = input.data();
    U actual = r(d);
    if (actual == expected) return 0;
    std::cerr << std::hex << "Decoding " << encoding << "; " << input << " gave " << actual
              << " instead of " << expected << std::endl;
    return 1;
}

int test_write(int encoding, U input, std::vector<u> expected)
{
    o = encoding;
    u buf[20], *p = buf;
    w(input, p);
    std::vector<u> actual(buf,p);
    if (expected == actual) return 0;
    std::cerr << std::hex << "Encoding " << encoding << "; " << input << " gave " << actual
              << " instead of " << expected << std::endl;
    return 1;
}

int test_transcode(int ienc, std::vector<u> input, int oenc, std::vector<u> expected)
{
    b = 0;
    i = ienc; o = oenc;
    u buf[200], *p = buf, *d = input.data();
    int result = t(d, p);
    std::vector<u> actual(buf,p);
    if (result ? expected.empty() : expected == actual) return 0;
    std::cerr << std::hex << "Encoding " << ienc << " to " << oenc << "; " << input << " gave " << actual
              << " instead of " << expected << std::endl;
    return 1;
}

ชุดทดสอบ

static const U FAIL = ~0;
int main() {
    int e = 0;                        // error count
    // UTF-8
    e += test_read(0, { 128 }, FAIL); // unexpected continuation
    e += test_read(0, { 128, 1 }, FAIL);
    e += test_read(0, { 128, 128 }, FAIL);
    e += test_read(0, { 192, 192 }, FAIL); // start without continuation
    e += test_read(0, { 192, 0 }, FAIL);
    e += test_read(0, { 224, 0 }, FAIL);
    e += test_read(0, { 224, 192 }, FAIL);
    e += test_read(0, { 0xf4, 0x90, 128, 128 }, FAIL); // Unicode maximum+1

    e += test_read(0, { 127 }, 127);
    e += test_read(0, { 192, 129 }, 1); // We accept overlong UTF-8
    e += test_read(0, { 0xc2, 128 }, 128);
    e += test_read(0, { 224, 128, 129 }, 1);
    e += test_read(0, { 0xef, 128, 128 }, 0xF000);
    e += test_read(0, { 0xef, 191, 191 }, 0xFFFF);
    e += test_read(0, { 0xf4, 128, 128, 128 }, 0x100000);
    e += test_read(0, { 0xf4, 0x8f, 191, 191 }, 0x10FFFF); // Unicode maximum

    e += test_read(0, { 0xEF, 0xBB, 0xBF, 127 }, 127); // byte-order mark

    e += test_write(0, 0, { 0 });
    e += test_write(0, 127, { 127 });
    e += test_write(0, 128, { 0xc2, 128 });
    e += test_write(0, 255, { 0xc3, 191 });
    e += test_write(0, 0xFFFF, { 0xef, 191, 191 });
    e += test_write(0, 0x10FFFF, { 0xf4, 0x8f, 191, 191 });

    // UTF-16
    e += test_read(1, { 0, 1 }, 1);
    e += test_read(1, { 0xd8, 0, 0xdc, 1 }, 0x10001);
    e += test_read(1, { 0xdb, 0xff, 0xdf, 0xff }, 0x10ffff);

    e += test_read(1, { 0xd8, 0, 0xd8, 1 }, FAIL); // mismatched surrogate
    e += test_read(1, { 0xd8, 0, 0, 1 }, FAIL); // mismatched surrogate
    e += test_read(1, { 0xdc, 0 }, FAIL);

    e += test_write(1, 1, { 0, 1 });
    e += test_write(1, 256, { 1, 0 });
    e += test_write(1, 0xffff, { 255, 255 });
    e += test_write(1, 0x10001, { 0xd8, 0, 0xdc, 1 });
    e += test_write(1, 0x10ffff, { 0xdb, 0xff, 0xdf, 0xff });

    // UTF-16LE
    e += test_write(3, 1, { 1, 0 });
    e += test_write(3, 256, { 0, 1 });
    e += test_write(3, 0x10001, { 0, 0xd8, 1, 0xdc });
    e += test_write(3, 0x10fffe, { 0xff, 0xdb, 0xfe, 0xdf });

    // UTF-16 byte-order mark
    e += test_read(1, { 0xFE, 0xFF, 0x0, 1 }, 1); // byte-order mark
    e += test_read(1, { 0xFF, 0xFE, 1, 0x0 }, 1); // reversed byte-order mark
    // disallowed byte-order marks
    e += test_read(2, { 0xFE, 0xFF }, FAIL);
    e += test_read(3, { 0xFF, 0xFE }, FAIL);
    // reversed byte-order mark is an unassigned character - to be treated like regular character, according to question
    e += test_read(2, { 0xFF, 0xFE }, 0xfffe);
    e += test_read(3, { 0xFE, 0xFF }, 0xfffe);

    // UTF-32
    e += test_read(4, { 0, 0, 0, 1 }, 1);
    e += test_read(4, { 1, 0, 0, 0 }, FAIL);
    e += test_write(4, 1, { 0, 0, 0, 1 });
    e += test_write(4, 0x10203, { 0, 1, 2, 3 });

    // UTF-32LE
    e += test_read(6, { 0, 0, 0, 1 }, FAIL);
    e += test_read(6, { 1, 0, 0, 0 }, 1);

    // UTF-32 byte-order mark
    e += test_read(4, { 0, 0, 0xFE, 0xFF,  0, 0, 0, 1 }, 1); // byte-order mark
    e += test_read(4, { 0xFF, 0xFE, 0, 0,  1, 0, 0, 0 }, 1); // reversed byte-order mark
    // disallowed byte-order marks
    e += test_read(5, { 0, 0, 0xFE, 0xFF }, FAIL);
    e += test_read(5, { 0xFF, 0xFE, 0, 0 }, FAIL);
    e += test_read(6, { 0, 0, 0xFE, 0xFF }, FAIL);
    e += test_read(6, { 0xFF, 0xFE, 0, 0 }, FAIL);

    e += test_transcode(1, { 1, 2, 0xFE, 0xFF, 0, 0 }, // That's not a BOM; it's a zwnj when not the first char
                        1, { 1, 2, 0xFE, 0xFF, 0, 0 });
    e += test_transcode(1, { 0xFF, 0xFE, 1, 2, 0, 0 }, // reversed byte-order mark implies little-endian
                        1, { 2, 1, 0, 0 });
    e += test_transcode(4, { 0xFF, 0xFE, 0, 0, 1, 2, 0, 0, 0, 0 }, // reversed BOM means little-endian
                        4, { 0, 0, 2, 1, 0, 0, 0, 0 });
    e += test_transcode(1, { 0xdb, 0xff, 0xdf, 0xff, 0, 0 }, // U+10ffff UTF-16 to UTF-8
                        0, { 0xf4, 0x8f, 191, 191, 0 });

    return e;
}

แดง .. C ++ เอาชนะ Python
TickTock

5

Python - 1367 UTF-8 ตัวอักษร

เอาล่ะ! นี่เป็นคำถามที่ยากมากเพราะจากจำนวนงานที่ต้องใช้เพื่อทำความเข้าใจและปฏิบัติตามข้อกำหนดทั้งหมด แต่ฉันคิดว่าฉันมีการใช้งานที่ถูกต้อง

O,P,Q,R=65536,128,b'\xff\xfe\x00\x00',63
def A(x,y):assert x;return y
def B(x):
    o,c=[],0
    for b in x:
        if c:c,v=c-1,A(127<b<192,v<<6)|(b-P)
        else:
            c,v=(b>127)+(b>223)+(b>239),b
            if b>127:v=A(191<b<248,b&(R>>c))
        o+=[v][c:]
    return o[o[0]in(65279,O-2):]
def C(k):
    def o(x,s=None):
        for a,b in zip(x[k::2],x[1-k::2]):
            d=a|(b<<8)
            if s!=None:yield(A(56319<d<57344,d-56320)|(s<<10))+O;s=None
            elif 55295<d<57344:s=A(s<1024,d-55296)
            else:yield d
    return o
def D(x):n=(2,3,1)[[Q[:2],Q[1::-1],x[:2]].index(x[:2])];return C(n&1)(x[n&2:])
E=lambda a,b,c,d:lambda x:[L|(l<<8)|(m<<16) for L,l,m in zip(x[a::4],x[b::4],x[c::4])]
def F(x):n,m=((1,4),(-1,4),(-1,0))[[Q,Q[::-1],x[:4]].index(x[:4])];return E(*range(4)[::n])(x[m:])
S=lambda x,s=0,a=255:(x>>s)&a
G=lambda e:(e,)if e<P else(192|S(e,6),P|(e&R))if e<2048 else(224|S(e,12),P|S(e,6,R),P|(e&R))if e<O else(240|S(e,18),P|S(e,12,R),P|S(e,6,R),P|(e&R))
H=lambda e:(S(e,8),S(e))if e<O else(216|S(e-O,18),S(e-O,10),220+S((e-O)&1023,8),S(e-O))
I=lambda e:(S(e),S(e,8))if e<O else(S(e-O,10),216|S(e-O,18),S(e-O),220+S((e-O)&1023,8))
J=lambda e:(S(e,24),S(e,16),S(e,8),S(e))
K=lambda e:(S(e),S(e,8),S(e,16),S(e,24))
convert=lambda d,i,o:bytes(sum(map(L[o],N(list(M[i](d)))),()))if d else d
L,M=[G,H,H,I,J,J,K],[B,D,C(1),C(0),F,E(3,2,1,0),E(0,1,2,3)]
N=lambda d:[A(-1<x<1114112 and x&~2047!=55296,x)for x in d]

convertเป็นฟังก์ชั่นที่ใช้ข้อมูลวัตถุ 'ไบต์', ID อินพุตและ ID ผลลัพธ์ ดูเหมือนว่าจะใช้งานได้แม้ว่า python จะมีการใช้งาน BOM เล็กน้อยเมื่อไม่ระบุในการเข้ารหัสดังนั้นการใช้การเข้ารหัสแบบ builtin ของ python ในการทดสอบโหมด 1 และ 4 จะไม่ทำงาน

เรื่องสนุก: ขนาดก็คือ 555 16หรือ 10101010101 2 2

773 chars สำหรับการถอดรหัส 452 สำหรับการเข้ารหัส 59 สำหรับการตรวจสอบและ 83 สำหรับชิ้นส่วนเบ็ดเตล็ด


@TrangOul: โดยทั่วไปการแก้ไขเล็กน้อย (เช่นการติดแท็กภาษา) ถูกทำให้ขมวดคิ้ว
Zach Gates


คำถาม / คำตอบนั้นไม่ได้แสดงถึงฉันทามติของชุมชน ข้ามเครือข่ายมีการแก้ไขเล็กน้อยเช่นนี้ ผู้ใช้ตัวแทน <1,000 หรือ> 1,000 คนไม่ควรทำการแก้ไขเหล่านี้เว้นแต่จะปรับปรุงเนื้อหาหรือรูปแบบให้ชัดเจน เป็นการดีที่สุดที่จะระงับการแก้ไขสิ่งต่าง ๆ เช่นแท็กภาษาการแก้ไข / แก้ไขคำเดี่ยว ฯลฯ @cat
Zach Gates

ฉันคิดว่าขนาดนั้นจะไม่มีอีกต่อไป 0x555 :-( แต่คุณอาจเข้าใกล้กับส่วนปลาย Python-golf มาตรฐานของการใช้ที่ว่างหนึ่งอันสำหรับการเยื้อง
Toby Speight

@TobySpeight มันคือ 0x557 ตอนนี้คุณพูดถูก และจริงๆแล้วฉันใช้แท็บซึ่งจะต้องถูกแปลงเป็นช่องว่างสำหรับการโพสต์ แต่ก็ยังนับเป็นตัวละครตัวหนึ่ง ฉันจะไปดูว่าฉันสามารถโกนตัวละครได้สองทางถ้าฉันมีโอกาส
Cel Skeggs

4

Python 3, 1138 ไบต์ (UTF-8)

ดังนั้นปรากฎว่าการเดินทางระหว่างประเทศ 14 ชั่วโมงเป็นโอกาสอันยอดเยี่ยมที่จะจัดการแข่งขันกอล์ฟ ...

C()ฟังก์ชั่นการแปลง สายนี้u(), v()และw()การถอดรหัสและU(), V()และW()การเข้ารหัส UTF-8 -16 และ -32 ตามลำดับ ไม่มีตัวเข้ารหัสจะส่งออก BOM แต่ตัวถอดรหัสทั้งหมดจะจัดการอย่างถูกต้อง เงื่อนไขข้อผิดพลาดส่งผลให้เกิดข้อยกเว้น (ซึ่งโดยปกติจะเป็นZeroDivisionErrorฟังก์ชันที่ "จู่ ๆ ก็" E())

from struct import*
l=len
j=''.join
b=lambda c:[*bin(c)[2:]]
P,Q,i,o,z,Z='HI10><'
B=65279
O,F,H,L,X=1024,65536,55296,56320,57344
E=lambda:1/0
R=lambda y,e,c,n:unpack(([[z,Z][y[:n]==pack(Z+c,B)],e][l(e)])+c*(l(y)//n),y)
S=lambda d,e:B!=d[0]and d or e and E()or d[1:]
def u(y,d=(),p=0):
 while p<l(y):
  q=b(y[p])
  if l(q)>7:
   x=q.index(o);C=1<x<5and q[x+1:]or E();X=x+p;X>l(y)>E();p+=1
   while p<X:q=b(y[p]);C=l(q)>7and(i,o==q[:2])and(*C,*q[2:])or E();p+=1
   d=*d,int(j(C),2)
  else:d=*d,y[p];p+=1
 return S(d,0)
def T(p):
 q=b(p);C=()
 while l(q)not in(7,11,16,21):q=o,*q
 while l(q)>6:C=int(i+o+j(q[-6:]),2),*C;q=q[:-6]
 return bytes(p<128and[p]or[int(i*(7-l(q))+o+j(q),2),*C])
U=lambda c:b''.join(map(T,c))
def v(y,e=''):
 c=R(y,e,P,2);d=[];n=0
 while n<l(c)-1:h,a=c[n:n+2];D=[(h,a),(F+(h-H)*O+a-L,)][H<=h<L<=a<X];M=3-l(D);n+=M;d+=D[:M]
 if n<l(c):d=*d,c[n]
 return S(d,e)
V=lambda c,e=z:W(sum(map(lambda p:([H+(p-F)//O,L+(p-F)%O],[p])[p<F],c),[]),e,P)
w=lambda y,e='':S(R(y,e,Q,4),e)
W=lambda c,e=z,C=Q:pack(e+C*l(c),*c)
K=(u,U),(v,V),(v,V,z),(v,V,Z),(w,W),(w,W,z),(w,W,Z)
def C(y,f,t):f,_,*a=K[f];_,t,*b=K[t];return t(f(y,*a),*b)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.