UTF-8とは?現代Webを支えるEncodingを解説
UTF-8は、1つのpageにEnglish、日本語、Thai、Chinese、Arabic、mathematical symbols、emojiを同時に載せられるencodingです。ここではその仕組みと、modern webのdefaultになった理由を解説します。
目次
UTF-8とは?
UTF-8はUnicode Transformation Format - 8-bitの略で、Unicode standardのすべてのcharacterを表せるvariable-width character encodingです。
各characterを1から4 bytesで保存します。A、z、5、!のようなbasic ASCII charactersは1 byte、accented letters、日本語、Thai characters、Chinese characters、emojiは必要に応じて複数bytesを使います。
UTF-8は1992年にKen ThompsonとRob Pikeによって設計されました。現在ではwebsites、APIs、source code、databases、configuration filesで主流のtext encodingです。
UnicodeとUTF-8の違い
UnicodeとUTF-8は混同されがちですが、同じ問題の別の部分を解決します。
- Unicodeはcharacter setです。各characterにunique code pointを割り当てる巨大なcatalogで、たとえばAはU+0041、Euro signはU+20ACです。
- UTF-8はencodingです。Unicode code pointsを、computersが保存・送信・読み取りできるbytesへ変換する実用的な方法です。
たとえるなら、Unicodeはcharactersとnumbersのdictionaryで、UTF-8はそのnumbersをbytesへ詰めるdelivery formatです。UTF-16やUTF-32のような他のUnicode encodingsもありますが、UTF-8はcompactでASCIIとのbackward compatibilityがあるためWeb standardになりました。
UTF-8 Encodingの仕組み
UTF-8はvariable-width byte patternを使います。必要なbytes数はUnicode code pointの値で決まります。
| Code Point Range | Bytes | Byte Pattern | 例 |
|---|---|---|---|
| U+0000 - U+007F | 1 | 0xxxxxxx | A, z, 5, ! |
| U+0080 - U+07FF | 2 | 110xxxxx 10xxxxxx | é, ñ, ü |
| U+0800 - U+FFFF | 3 | あ, €, 中, ✓ | |
| U+10000 - U+10FFFF | 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | emojiやrare historic scripts |
各byteのleading bitsは、decoderにそのbyteの種類を伝えます。
- 先頭が
0: single-byte ASCII character。 - 先頭が
110: 2-byte characterのfirst byte。 - 先頭が
1110: 3-byte characterのfirst byte。 - 先頭が
11110: 4-byte characterのfirst byte。 - 先頭が
10: continuation byteであり、characterの開始ではありません。
この設計によりUTF-8はself-synchronizingです。programがbyte streamの途中から読み始めても、10で始まらないbyteを見つけるまで進めば、次のcharacter boundaryを回復できます。
Step-by-Step Encoding Examples
1-byte: "A" (U+0041)
Code point: U+0041 = 65 = 1000001 in binary
Range: U+0000-U+007F -> 1 byte
Pattern: 0xxxxxxx
Fill in: 0 1000001
Byte: 01000001 = 0x41
"A" in UTF-8 = 0x41 (identical to ASCII)2-byte: accented e (U+00E9)
Code point: U+00E9 = 233 = 11101001 in binary
Range: U+0080-U+07FF -> 2 bytes
Pattern: 110xxxxx 10xxxxxx
Split bits: 00011 101001
Fill in: 11000011 10101001
Bytes: 0xC3 0xA9
"e with acute" in UTF-8 = 0xC3 0xA93-byte: Euro sign (U+20AC)
Code point: U+20AC = 8364 = 10000010101100 in binary
Range: U+0800-U+FFFF -> 3 bytes
Pattern: 1110xxxx 10xxxxxx 10xxxxxx
Split bits: 0010 000010 101100
Fill in: 11100010 10000010 10101100
Bytes: 0xE2 0x82 0xAC
"Euro sign" in UTF-8 = 0xE2 0x82 0xAC4-byte: grinning face emoji (U+1F600)
Code point: U+1F600 = 128512
Range: U+10000-U+10FFFF -> 4 bytes
Pattern: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Split bits: 000 011111 011000 000000
Fill in: 11110000 10011111 10011000 10000000
Bytes: 0xF0 0x9F 0x98 0x80
"grinning face emoji" in UTF-8 = 0xF0 0x9F 0x98 0x80UTF-8が主流になった理由
UTF-8がdominant encodingになったのには、実用的な理由があります。
- ASCIIとのbackward compatibility - 既存のASCII documentsはそのままvalid UTF-8です。
- Space efficient - English textは1 characterあたり1 byteで、他のscriptsも必要なbytesだけを使います。
- Byte-order issuesがない - UTF-16やUTF-32と違い、UTF-8ではbyte-order switchingが不要です。
- Self-synchronizing - errorsやrandom seekingの後でも、programsはcharacter boundariesを回復できます。
- C-style stringsと相性がよい - ordinary textに予期しないnull bytesが入りません。
- Universal - basic Latinから日本語、Thai text、emojiまで、すべてのUnicode characterを表せます。
UTF-8 vs UTF-16 vs UTF-32
Unicodeには主なencodingsが3つあります。tradeoffsは次の通りです。
| Feature | UTF-8 | UTF-16 | UTF-32 |
|---|---|---|---|
| Bytes per character | 1-4 | 2 or 4 | 常に4 |
| ASCII compatible | Yes | No | No |
| Byte order issue | No | Yes, BOMが必要な場合あり | Yes, BOMが必要な場合あり |
| "Hello" size | 5 bytes | 10 bytes | 20 bytes |
| Common use | Web, Linux, macOS, JSON | Windows APIs, Java, JavaScript internals | Internal processing |
| Web usage | Dominant | 非常にまれ | ほぼ使われない |
UTF-16は今も重要です。JavaScriptとJavaはstringsの内部表現に16-bit code unitsを使うためです。そのためemojiやsupplementary charactersが含まれると、string lengthとvisible character countが直感とずれることがあります。
CodeでのUTF-8
多くのmodern languagesとbrowsersにはUTF-8 toolsが組み込まれています。
JavaScript
// Encode string to UTF-8 bytes
const encoder = new TextEncoder();
const bytes = encoder.encode("Hello €");
console.log(bytes);
// Uint8Array [72, 101, 108, 108, 111, 32, 226, 130, 172]
// Decode UTF-8 bytes back to string
const decoder = new TextDecoder("utf-8");
const text = decoder.decode(bytes);
console.log(text); // "Hello €"
// Character length is not always byte length
"Hello".length; // 5
new TextEncoder().encode("Hello").length; // 5
new TextEncoder().encode("cafe").length; // 4
new TextEncoder().encode("café").length; // 5Python
# Encode string to UTF-8 bytes
text = "Hello €"
utf8_bytes = text.encode("utf-8")
print(utf8_bytes) # b'Hello \xe2\x82\xac'
print(len(utf8_bytes)) # 9 bytes
# Decode UTF-8 bytes to string
decoded = utf8_bytes.decode("utf-8")
print(decoded) # "Hello €"
# Character vs byte length
len("café") # 4 characters
len("café".encode("utf-8")) # 5 bytesHTML
<!-- Always declare UTF-8 in HTML -->
<meta charset="UTF-8">
<!-- Put it early inside <head>, before text content that needs decoding -->よくあるUTF-8 Problems
多くのencoding bugsは、bytesをwrong encodingで読んだり、bytesとcharactersを混同したりすることで起きます。
Mojibake (文字化け)
UTF-8 bytesをLatin-1やWindows-1252としてdecodeすると、読みやすいtextが奇妙なcharactersに変わることがあります。writerとreaderの両方がUTF-8を使うようにします。
Replacement characters
decoderがvalid UTF-8ではないbytesを見つけると、replacement character U+FFFDが表示されます。original file encodingを確認し、double-decodingを避けます。
BOM surprises
一部のtoolsはfilesの先頭にUTF-8 Byte Order Markを追加します。JSON、shell scripts、strict parsersを壊すことがあるため、可能ならUTF-8 without BOMで保存します。
Character length vs byte length
10-character stringが10 bytesとは限らず、もっと大きい場合があります。UIにはcharacter-aware limits、storageやnetwork constraintsにはbyte-aware limitsを使います。
Best Practices
encoding problemsを避けるには、次の習慣が役立ちます。
- UTF-8をdefaultで使う。specific legacy requirementがある場合を除きます。
- Encodingを宣言する。HTMLでは
<meta charset="UTF-8">、HTTP headersではcharset=utf-8を使います。 - Source filesをUTF-8で保存する。codeやdata filesでは、できればBOMなしを使います。
- MySQLではutf8mb4を使う。emojiを含むfull Unicodeを保存できるようにします。
- Raw UTF-8 bytesを不用意に分割しない。user-visible textではcharacters、code points、grapheme clusters単位で扱います。
- Multilingual textでtestする。usersがreal-world names、addresses、messagesを貼り付ける前にbugsを見つけられます。
UTF-8 TextをEncode & Decode
無料のUTF-8 Converter toolで、byte sequencesの確認、textのencode、bytesのdecodeをbrowser内ですぐに行えます。
UTF-8 Converterを試す参考資料
- Yergeau, F. (2003). UTF-8, a transformation format of ISO 10646. RFC 3629, IETF. https://datatracker.ietf.org/doc/html/rfc3629
- Pike, R. & Thompson, K. (2003). UTF-8 history. https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt
- The Unicode Consortium. The Unicode Standard. https://www.unicode.org/standard/standard.html
- Mozilla Developer Network. TextEncoder - Web APIs. https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
- W3Techs. Usage statistics of character encodings for websites. https://w3techs.com/technologies/overview/character_encoding