Base62란 무엇인가?
Base62는 숫자를 어디에 붙여넣어도 살아남는 문자만으로 쓰는 방법입니다. 숫자 10개, 대문자 26개, 소문자 26개. 구두점도 공백도 패딩 문자도, URL·파일 이름·쿠키·데이터베이스 키에 넣기 전에 이스케이프해야 할 것이 없습니다. 10 더하기 26 더하기 26은 62이고, 이름은 거기서 왔습니다.
30초 버전: 숫자 12345는 3D7로, 1234567890은 1LY7VK로 쓰입니다. 반대 방향은 같은 연산의 역이며, 코드를 만든 정확한 알파벳이 필요합니다 — 다른 알파벳은 같은 여섯 문자를 오류 메시지 없이 다른 숫자로 되돌립니다.
이 페이지는 관련된 두 가지 일을 하며, 그 차이는 이 페이지의 다른 무엇보다 중요합니다:
- 정수 모드는 입력을 숫자로 다룹니다.
1234567890 같은 10진 ID는 1LY7VK가 되고, 입력의 선행 0은 값의 일부가 아니라 돌아오지 않습니다. - 바이트 모드는 입력을 바이트 문자열로 다룹니다. 바이트를 하나의 거대한 빅엔디언 정수로 읽어 62로 나눕니다. 같은 산술을 다른 대상에 적용한 것입니다. 여기서는 선행 0 바이트 수가 0 바이트당 0 문자 하나로 살아남습니다.
62라는 수의 출처와 그 대가
62는 2의 거듭제곱이 아니며, 이 사실 하나가 나머지 전부를 규정합니다. 익숙한 인코딩은 입력을 고정 비트 묶음으로 자릅니다. 4비트가 hex 문자 하나, 6비트가 Base64 문자 하나, 5비트가 Base32 문자 하나. Base62는 그렇게 못 합니다. 62개 값에 맞는 정수 비트 수가 없기 때문입니다 — 5비트는 32개, 6비트는 64개를 나타냅니다. 그래서 Base62는 산술을 거칩니다. 입력 전체를 하나의 정수로 읽고 62진으로 출력합니다.
문자 하나는 log2(62) = 5.954비트를 실으며 Base64의 6과 아주 가깝고, 10진 모드에서는 문자 하나가 log62(10) = 1.792자리의 10진수를 대체합니다. 길이를 고르기 전에 알아둘 만한 결과들:
| 코드 길이 | 나타낼 수 있는 값 | 실무에서 |
| 4자 | 624 = 14,776,336 | 여덟 자리 미만 카운터면 충분하고 전화번호 한 통 분량에 들어갑니다. |
| 6자 | 626 = 56,800,235,584 | ID 코드의 보통 모양. 10자리 10진 ID가 여섯 문자에 들어갑니다. |
| 7자 | 627 = 3,521,614,606,208 | 32비트 카운터 범위를 두 자릿수 넘으며, 단축 링크 슬러그 폭입니다. |
| 11자 | 6211 = 52,036,560,683,837,093,888 | 264 = 18,446,744,073,709,551,616보다 크므로 64비트 전체가 열한 문자에 들어갑니다. |
반대 방향으로는 10진 1,000자리가 약 558자, 4,096자리가 2,285자 필요합니다. 절약은 실재하지만 유한합니다. Base62는 10진수를 대략 44% 줄이며, 문자당 5.954비트가 6.4나 6.5보다 작은 이상 가장 조밀한 인쇄 가능 인코딩을 이기지 못합니다.
정수 모드: 선행 0은 어떻게 되나
정수에는 표준적인 표기가 하나 있고 알파벳의 0 문자로 시작합니다. 숫자 우선 두 배치에서는 0, 글자 우선 배치에서는 A입니다. 첫 유효 문자 왼쪽은 전부 패딩이며 패딩은 값의 일부가 아닙니다. 00012345와 12345는 모두 3D7이 됩니다. 고정 폭이 필요하면 — 예를 들어 열에서 줄맞춤이 필요한 7자 코드 — 페이지의 고정 폭으로 패딩 상자가 폭에 도달할 때까지 0 문자를 반복합니다. 12345를 폭 7로 출력하면 숫자 우선 알파벳에서 00003D7, 글자 우선에서 AAAADNH입니다. 패딩은 겉치레입니다. 선행 문자는 값에 아무것도 더하지 않으며 두 문자열을 디코딩하면 모두 12345가 돌아옵니다. 0 × 626과 0 × 625는 0을 표기하는 문자가 무엇이든 0이기 때문입니다.
따라서 패딩된 문자열의 디코딩도 동작하며, 페이지는 선행 문자 중 몇 개가 0 문자였는지 보고해 “코드가 7자”와 “값은 3자면 충분했다”의 차이가 결코 수수께끼가 되지 않게 합니다.
바이트 모드: 바이트 문자열에 같은 산술
바이트 모드는 입력 바이트를 하나의 빅엔디언 정수로 읽습니다 — 바이트 문자열 전체가 아무리 길어도 하나의 숫자로 취급됩니다 — 그리고 그 숫자를 62진으로 출력합니다. 바이트는 8비트를 담고 문자는 그중 5.954개를 나타내므로 바이트 모드는 압축이 아닙니다. 입력 크기의 약 134%가 필요하며 Base64의 133%보다 살짝 나쁩니다. 위 크기 표의 92바이트 샘플에서 92바이트는 Base62 124자로 출력되고 Base64도 124자입니다(= 패딩 전 123자). Base62는 밀도에서 지고 문자 안전성에서 이기며, 이것이 모든 단축 링크와 초대 코드가 일부러 택하는 거래입니다.
선행 0 바이트는 보존되며, 이것은 양쪽 방향에서 틀리기 쉽습니다. 선행 0 바이트 둘 뒤에 0x01이 오는 문자열은 숫자 우선 알파벳에서 001, 글자 우선에서 AAB로 출력됩니다. 선행 문자가 0을 표기하며 0 바이트당 하나이기 때문입니다. 0x00 한 바이트는 단일 문자 0으로, 0x01 한 바이트는 1로 출력됩니다. 같은 알고리즘을 돌리는데 바이트 모드와 정수 모드가 다르게 보이는 유일한 지점입니다.
이 모든 것의 대가로 바이트 모드는 산술의 제곱 시간을 물려받습니다. 1,024바이트는 약 3분의 1초, 2,048바이트는 약 1.3초로 추정되며, 위 한계 표와 같은 수치입니다. 그래서 이 페이지의 바이트 모드는 나갈 때 2,048바이트, 들어올 때 2,048자에서 멈춥니다 — 2,048바이트는 약 2,751자로 출력되어 이 페이지를 왕복하는 페이로드는 약 1,520바이트가 최대입니다 — 그리고 이 페이지의 바이트 모드는 작은 값의 참조이지 실제 파일에서 Base64나 Base91의 대체가 아닙니다.
세 알파벳, 그리고 알파벳이 전부인 이유
알파벳의 문자는 고정된 순서이며 문자의 값은 그 순서에서의 위치입니다. 순서를 옮기면 모든 문자의 의미가 바뀝니다. 널리 쓰이는 배치는 세 가지이고, 같은 숫자를 세 방식으로 쓰면:
| 10진수 | 0-9, A-Z, a-z | 0-9, a-z, A-Z | A-Z a-z, 0-9 |
| 0 | 0 | 0 | A |
| 61 | z | Z | 9 |
| 62 | 10 | 10 | BA |
| 12,345 | 3D7 | 3d7 | DNH |
| 1,234,567,890 | 1LY7VK | 1ly7vk | BViHfU |
마지막 세 열을 하나의 알파벳으로 읽으면 하나의 정합적 방식입니다. 서로 바꿔 쓸 수 있는 것으로 읽으면 무너집니다. 디코딩은 최악의 방식으로 알파벳에 눈멀기 때문입니다. 입력의 어떤 문자든 세 알파벳 모두에 있어서, 잘못된 알파벳은 오류를 내지 않고 다른 숫자만 냅니다.
| 코드 | 0-9 A-Z a-z로 읽으면 | 0-9 a-z A-Z로 읽으면 | A-Z a-z 0-9로 읽으면 |
| 3D7 | 12,345 | 13,957 | 211,665 |
| 1LY7VK | 1,234,567,890 | 1,624,950,792 | 48,723,527,772 |
대소문자는 같은 함정의 더 날카로운 버전입니다. Base62는 모든 배치에서 대소문자를 구분하므로 코드를 소문자화하면 조용히 다시 쓰입니다. 1LY7VK는 숫자 우선 알파벳에서 1,234,567,890이고 1ly7vk는 같은 알파벳에서 1,624,950,792입니다 — 그리고 그것은 숫자-소문자 배치에서 우연히 1,234,567,890인데, 그 배치가 정확히 숫자 우선 배치의 대소문자 두 벌을 맞바꾼 것이기 때문입니다. 0 문자도 공유되지 않습니다. 숫자 우선 두 배치는 0을 0으로 쓰고 글자 우선 배치는 A로 써서 그 알파벳은 숫자로 시작하지 않습니다.
다른 인코딩 옆의 Base62
| 인코딩 | 문자당 비트 | 입력 대비 크기 | 비고 |
| Base16(16진수) | 4 | 200% | 바이트당 두 문자, 한눈에 읽히고 알파벳을 찾아볼 필요가 없습니다. |
| Base32 | 5 | 160% | 대소문자를 구분하지 않아 사람이 말로 전하기 좋지만, 이 묶음에서 가장 낭비가 큽니다. |
| Base36(0-9 a-z) | 약 5.17 | 약 155% | 숫자와 소문자만 있어 소문자화 파이프라인을 견뎌냅니다. 12345는 9ix로 씁니다. |
| Base58 | 약 5.86 | 약 137% | 밀도가 아니라 주소를 위해 태어났습니다: 헷갈리기 쉬운 네 문자를 정렬하는 대신 아예 뺐습니다. Base32 / Base58 인코딩 변환기 참조. |
| Base62 | 약 5.95 | 약 134% | 모든 문자가 숫자나 문자여서 이스케이프할 일이 없습니다. 밀도는 Base58과 Base64 사이입니다. |
| Base64 | 6 | 133% | 어디서나 기본 선택이지만, +, /, = 세 문자를 반드시 이스케이프해야 하는 대가가 따릅니다. Base64 변환기 참조. |
| Ascii85 / Base85 | 6.4 | 125% | 4바이트를 5문자로 쓰지만 85로 나누어떨어져 알파벳에 따옴표가 필요합니다. Ascii85 변환기 참조. |
| Base91 | 약 6.5 | 약 123% | 이 묶음에서 밀도가 가장 높고, 출력을 이스케이프 없이 붙여넣기에는 가장 위험합니다. Base91 인코더/디코더 참조. |
백분율은 반올림한 점근 비용입니다. 실제 92바이트 입력의 측정 문자 수는 이 페이지 위쪽 크기 표에 있습니다. 정수 모드에서 비교는 반대 방향으로 돕니다. 입력이 바이트가 아니라 10진 텍스트이기 때문입니다. 거기서 Base62는 대체하는 자릿수보다 약 44% 짧고 Base36은 약 36% 짧아서, ID 코드가 보통 Base58이 아니라 Base62나 Base36인 이유입니다.
Base62가 아닌 것들
- 표준이 아닙니다. RFC도 사양도 없습니다. 그 어느 표준 기구도 Base62를 정의한 적이 없어서 알파벳이 보장되지 않고, 이 페이지가 하나를 조용히 고르는 대신 세 배치를 전부 인쇄하는 이유입니다.
- 암호화가 아닙니다. 진법 바꾸기일 뿐입니다. 알파벳을 아는 누구나 한 번에 되돌리며 키도 솔트도 어떤 비밀도 없습니다.
- 압축이 아닙니다. 바이트 모드는 데이터를 약 3분의 1 키웁니다. 정수 모드가 압축처럼 보이는 건 10진 텍스트가 애초에 숫자를 쓰는 비효율적인 방법이어서뿐입니다.
- 대소문자 무관이 아닙니다. Base32는 소문자화해도 읽히지만 Base62는 안 됩니다. 대소문자를 정규화하는 시스템을 거친 코드는 오염된 코드입니다.
- 자기 검증이 아닙니다. 체크섬도 검증 문자도 없어서 잘못된 문자 하나가 다른 값을 가진 그럴듯한 결과를 냅니다. 그것이 중요하면 Bitcoin 배치에 체크섬이 있습니다 — Base32 / Base58의 Base58Check 절을 보세요.
- 고정 길이가 아닙니다. 문자 수는 값과 함께 자라서 1에서 시작해 627에 도달하는 카운터는 한 글자에서 여덟 글자가 됩니다. 안정적인 열이 필요하면 고정 폭으로 패딩하세요.
실제로 물리는 함정
- 알파벳이 열 가지 수수께끼 중 아홉의 답입니다. 다른 도구가 같은 숫자에 다른 코드를 주면 버그를 의심하기 전에 두 알파벳을 글자 단위로 비교하세요. 위 표는 같은 값을 세 알파벳으로 보여주며 셋 다 올바릅니다.
- 잘못된 알파벳은 조용히 실패합니다. 그것에 대한 오류 경로가 없습니다.
3D7은 어떤 배치를 가정하느냐에 따라서만 12,345, 13,957 또는 211,665로 디코딩됩니다. 0 패드일 가능성이 가장 높은 첫 문자를 확인하고, 알파벳 앞쪽이 숫자인지 글자인지 확인하세요. - 선행 0은 두 가지 다른 것을 뜻합니다. 정수 모드에서
00012345와 12345는 같은 숫자이고 똑같이 출력됩니다. 바이트 모드에서 선행 0 바이트는 데이터이며 0 문자 하나 더로 출력됩니다. 그 문자 하나를 빼면 바이트 문자열이 달라집니다. - 대소문자 정규화가 코드를 파괴합니다. 이메일 주소, 호스트명, Windows 경로는 전송 중에 소문자화될 수 있습니다. Base62 코드는 그것을 survive할 수 없고 그것이 Base36이 여전히 존재하는 이유입니다.
- 긴 입력은 클 때만 아니라 느립니다. 변환은 입력 전체에 대한 산술이라 입력 길이가 두 배가 되면 시간이 네 배가 됩니다. 이 페이지는 멈추는 대신 측정된 한계를 넘는 입력을 거부합니다. 측정 수치는 위쪽 크기 표에 있습니다.
- Base62 문자열은 아무것도 증명하지 않습니다. 숫자와 글자의 거의 모든 문자열이 불평 없이 디코딩되므로 임의의 URL 슬러그도 어떤 숫자로 디코딩됩니다. 코드는 발급한 시스템이 매핑을 함께 저장할 때만 의미가 있습니다.
빠른 답
“왜 다른 Base62 도구는 같은 숫자에 다른 코드를 주나요?”
알파벳이 다르기 때문입니다. Base62에는 어긋날 사양이 없어 구현마다 배치를 고릅니다. 숫자-대문자 우선, 숫자-소문자 우선, 글자 우선. 이 페이지 상단의 알파벳 선택을 바꿔 세 답을 나란히 보세요.
“Base62는 URL에 안전한가요?”
네, 세 배치 모두에서 그렇습니다. 62 문자 전부가 이스케이프 없는 글자와 숫자라, 쿼리 문자열에서 퍼센트 삼중체로 확장되는 것도 없고 URL이나 경로 세그먼트, HTML 속성을 끝내는 것도 없습니다. 단축 링크가 Base64가 아니라 Base62인 이유 전부입니다.
“Base62와 Base64 중 어느 쪽이 작나요?”
바이트에서는 Base64가 아주 살짝 작습니다. 입력의 약 133% 대 약 134%. 위 92바이트 샘플에서 둘은 124자로 비깁니다. 10진수에서는 Base62가 텍스트를 약 44% 줄이며 실질적 이득은 거기 있습니다.
“이 페이지로 Base64 문자열을 디코딩할 수 있나요?”
아니요, 그리고 실패했다고 알려주지도 않습니다. 두 알파벳은 62 문자 전체에서 겹쳐서 Base64 문자열도 보통 여기서 “유효한” 입력이며 그냥 다른 숫자로 디코딩됩니다. Base64에는 Base64를 쓰세요.
“Base62 코드에 최대 길이가 있나요?”
이론상 알고리즘에 상한이 없습니다. 실무에서 이 페이지는 10진 4,096자리, 2,048바이트에서 멈춥니다. 뒤의 산술이 제곱형이라 이유를 보여줄 것 없이 탭이 얼기 때문입니다. 측정 수치는 위쪽 한계 표에 있습니다.
“이 페이지의 결과가 맞는지 어떻게 알죠?”
자체 테스트를 누르세요. 문서화된 모든 샘플, 0부터 64까지의 모든 바이트 길이, 그리고 10진수의 분포를 세 알파벳 전부로 돌려 반환값과 입력을 비교하고, 각 알파벳의 62 문자가 모두 URL에 안전한지 다시 검사합니다. 샘플 버튼은 세 결과를 이 페이지 데이터 파일에 기록된 값과 추가로 비교합니다. 그 값들은 이 사이트 테스트 도구에 보관된 두 번째 독립 큰 정수 구현으로 검증되었습니다.
표준과 출처
여기에 구현할 표준은 없습니다. Base62는 사양이 아니라 관례이며 위에 인쇄된 세 알파벳이 실제 소프트웨어에 나타나는 것들입니다. 이 페이지는 사이트 자체의 큰 정수 루틴으로 구현했습니다. 어떤 크기도 JavaScript 숫자 타입에 제한받지 않도록 자릿수 배열 위의 순수 산술로 작성되었습니다.
이 페이지의 텍스트는 이 사이트를 위해 작성되었습니다. 이 페이지의 모든 풀이 예제는 페이지 자신의 코드로 생성된 뒤 이 사이트 테스트 도구에 보관된, 네이티브 큰 정수를 쓰는 두 번째 독립 구현으로 검증되었습니다. 같은 구현이 데이터 파일의 샘플과 크기 표도 검증했습니다.