빠르고 쉬운 UTF-8
14806 단어 cppjavascript
텍스트는 보기보다 간단합니다!
모든 개발자는 조만간 텍스트로 작업하는 벽에 부딪히게 되며, 텍스트를 올바르게 조작하는 복잡성에 뛰어들면 사람들이 쉽게 겁을 먹을 수 있습니다.
왜 우리는 좋은 것을 가질 수 없습니까?
유니코드는 표준 표현을 제공하여 텍스트 작업을 크게 단순화하지만 모든 곳에서 사용되는 것은 아닙니다. UTF-8은 가장 널리 사용되는 문자 인코딩 방식이지만 짐작하셨겠지만 모든 곳에서 사용되는 것은 아닙니다. 역사적인 이유로 UTF-16은 JavaScript, Java, C#, Windows, Qt 및 ICU 프로젝트의 기본값으로 남아 있습니다. 자세한 내용은 http://utf8everywhere.org/를 참조하십시오.
UTF-8 대 ASCII, UTF-16, UTF-32
UTF-8로 이동하기 전에 다른 인코딩 체계와의 빠른 비교는 다음과 같습니다.
대부분의 경우 UTF-16이 안전하지 않습니까?
아니요. two most frequent emoji used in Twitter , ❤️ 및 😂를 고려하십시오. 대부분의 문자는 길이가 1인 것으로 취급되지만 이 이모티콘은 모두 두 개의 UTF-16 단위를 차지합니다. 자바스크립트의 예:
UTF-32를 사용할 수 없습니까?
UTF-32는 비효율적이며 텍스트를 저장하는 데 필요한 공간을 늘립니다. 일반적인 기대와 달리 UTF-32는 텍스트 조작을 위한 묘책도 아닙니다. 고정 너비이지만 단일 유니코드 코드 포인트만 나타내며 예를 들어 이모티콘과 같은 많은 문자는 코드 포인트의 조합으로 구성됩니다. 자바스크립트의 예:
코드 포인트 ≠ 문자
많은 문자가 단일 코드 포인트로 표시될 수 있지만 여러 코드 포인트에 걸쳐 있는 많은 문자도 있습니다.
예를 들어, 태국어에는 서로 다른 성조 및 모음 기호
อ อี อี้ อู้
가 있으며 모두 별도의 코드 포인트로 구성되며 별도로 입력하고 지울 수 있습니다.다양한 이모지는 조합과 변형으로 구성됩니다.
이것이 코드 포인트가 아니라면 무엇입니까? 문자소 클러스터here에 대해 자세히 알아보십시오.
UTF-8은 어떻게 저장됩니까?
UTF-8은 문자를 1~4바이트로 인코딩하고 접두사 비트를 사용하여 구분합니다. U+0000..U+10FFFF 범위의 모든 문자를 인코딩할 수 있습니다(UTF-16 범위로 제한됨).
(x represents code point bits)
0xxx-xxxx 1-byte sequence, 7-bit value
110x-xxxx 10xx-xxxx 2-byte sequence, 11-bit value
1110-xxxx 10xx-xxxx 10xx-xxxx 3-byte sequence, 16-bit value
1111-0xxx 10xx-xxxx 10xx-xxxx 10xx-xxxx 4-byte sequence, 21-bit value
UTF-32로 변환:
UTF-8 | UTF-32
---------------------------------------------------------------------
0ABC-DEFG | 0000-0000 0000-0000 0000-0000 0ABC-DEFG
110A-BCDE 10FG-HIJK | 0000-0000 0000-0000 0000-0ABC DEFG-HIJK
1110-ABCD 10EF-GHIJ 10KL-MNOP | 0000-0000 0000-0000 ABCD-EFGH IJKL-MNOP
1111-0ABC 10DE-FGHI 10JK-LMNO 10PQ-RSTU | 0000-0000 000A-BCDE FGHI-JKLM NOPQ-RSTU
바이트 접두사:
0
- 1바이트 시퀀스110
- 2바이트 시퀀스의 시작1110
- 3바이트 시퀀스의 시작11110
- 4바이트 시퀀스의 시작10
- UTF-8 연속 바이트잘 테스트된 오픈 소스 솔루션이 있다는 점을 감안할 때 처음부터 UTF-8 반복을 구현해야 하는 것은 그리 흔한 일이 아닙니다. 그러나 작동 방식을 이해하는 데 여전히 유용한 연습입니다. 다음은 C++에서 UTF-8 반복의 예입니다.
constexpr auto UTF8UnitMasks = std::array{
0b0011'1111, 0b0111'1111, 0b0001'1111, 0b0000'1111, 0b0000'0111};
int getUTF8Prefix(uint8_t c) {
if (c < 0b1000'0000) return 1; // 1-byte (ASCII)
else if (c < 0b1100'0000) return 0; // continuation
else if (c < 0b1110'0000) return 2; // 2-byte
else if (c < 0b1111'0000) return 3; // 3-byte
else if (c < 0b1111'1000) return 4; // 4-byte
else return -1; // invalid
}
// Returns the current code point and increments textBegin to the next one
int32_t nextUTF8(const char** textBegin, size_t size) {
if (!textBegin || !size) return -1;
auto& data = *reinterpret_cast<const unsigned char**>(textBegin);
auto units = getUTF8Prefix(data[0]); // count code point units
if (units < 1 || units > size) {
++data;
return -1;
}
// verify all subsequent units are continuation bytes, getUTF8Prefix(c) == 0
if (std::any_of(data + 1, data + units, getUTF8Prefix)) {
++data;
return -1;
}
auto value = int32_t(data[0]) & UTF8UnitMasks[units];
for (int i = 1; i < units; ++i) {
value = (value << 6) + (data[i] & UTF8UnitMasks[0]);
}
data += units;
// check for Unicode range and overlong encoding (e.g, ASCII in 2+ bytes)
switch (units) {
case 1: return value;
case 2: return value >= (1 << 7) ? value : -1;
case 3: return value >= (1 << 11) ? value : -1;
case 4: return value >= (1 << 16) && value <= 0x10FFFF ? value : -1;
default: return -1;
}
}
void example() {
auto text = std::string_view("สวัส\xFFดีครับ!"); // Hello in Thai + invalid
for (auto begin = text.begin(); begin < text.end();) {
std::cout << nextUTF8(&begin, text.end() - begin) << " ";
}
std::cout << std::endl;
// Output: 3626 3623 3633 3626 -1 3604 3637 3588 3619 3633 3610 33
// ^ 0xFF - invalid code point
}
이 게시물은 표면적인 정보일 뿐이지만 일부 기본 정보를 이해하는 데 도움이 될 것입니다.
Reference
이 문제에 관하여(빠르고 쉬운 UTF-8), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/vejmartin/utf-8-quick-and-easy-532f텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)