文字コード

ChatGPT君による。



文字コードとは、文字をコンピュータ上で扱うためのコード(符号)のことで、文字を数値に変換するための規則です。すなわち、この0と1の並びは「a」であるとか「あ」であるとか定めるのが文字コードです。文字コードには様々な種類があり、それぞれのコード体系によって文字と数値の関係が定められています。以下にいくつかの代表的な文字コードを紹介します。

  1. ASCII(アスキー)

    • アメリカの標準コードで、英数字や制御文字を扱うために作られました。

    • 7ビットで表され、128種類の文字を表すことができます。

  2. ISO 8859

    • ASCIIを拡張して、西ヨーロッパの言語に対応するためのコードです。

    • 8ビットで表され、256種類の文字を表すことができます。

  3. Shift JIS(シフトJIS)

    • 日本語を含む文字コードで、日本で広く使われています。

    • バイト数によって、ASCII文字と日本語の文字を切り替えることができます。

  4. EUC(Extended Unix Code)

    • 主にUnix系のシステムで使用される、日本語を含むマルチバイト文字コードです。

  5. Unicode(ユニコード)

    • 世界中のほぼ全ての文字を一つの文字コードに統合しようとする取り組みで、UTF-8、UTF-16、UTF-32などのエンコーディング方式があります。

    • UTF-8は、ASCIIと互換性があり、最も広く使われているエンコーディングの一つです。

文字コードの選択は、使用する言語や互換性、システムの要件によって異なります。例えば、ウェブページではUnicodeのUTF-8が広く使われています。これは多言語対応が可能で、エンコード・デコードの効率が良いためです。

エンコード:文字列を0と1の列にする。
デコード:0と1の列を文字列にする。

日本語などの多バイト文字を含むテキストの取り扱いでは、適切な文字コードを使うことが重要で、間違った文字コードでテキストを表示しようとすると、「文字化け」と呼ばれる現象が起こります。これは、テキストが意図した通りに表示されず、代わりに意味不明な文字や記号が表示されることを指します。

ASCII

ASCII(American Standard Code for Information Interchange、アメリカ情報交換標準コード)は、コンピュータで文字を表現するためのコードの一つで、英数字や制御文字、いくつかの記号を含んでいます。ASCIIは1963年にアメリカの国家規格として制定され、その後、情報技術におけるテキストの標準的な文字コードとして広く採用されました。

ASCIIの特徴

  1. 7ビット構造
    ASCIIは7ビット(ビットは0か1の値を持つ最小のデータ単位)で構成されており、それにより128種類((2^7 = 128))の異なる文字や記号を表現できます。

  2. 互換性
    ASCIIは後の多くの文字コードの基礎となり、例えば8ビットを使うISO 8859や、マルチバイトを使うUTF-8などでも、最初の128文字(0から127までのコードポイント)はASCIIと互換性を持っています。

  3. 制御文字
    ASCIIには、テキストとして表示されない「制御文字」が含まれています。例えば、ラインフィード(LF、新しい行に移動)、キャリッジリターン(CR、カーソルを行の先頭に移動)、ベル(BEL、警告音を鳴らす)などです。

ASCIIの範囲

  • 制御文字(0-31および127): デバイスの制御に用いられる非表示文字。

  • 印字可能文字(32-126): 英数字、句読点、特殊記号、スペースなどを含む表示可能な文字。

ASCIIの例

  • 文字 "A" は ASCII コードで 65 (2進数では 01000001)です。

  • 文字 "a" は ASCII コードで 97 (2進数では 01100001)です。

  • 文字 "0" は ASCII コードで 48 (2進数では 00110000)です。

ASCIIテーブル

Dec  Hex  Bin    Char  | Dec  Hex  Bin      Char
-----------------------|-----------------------------
  0   00  0000000 NUL  |  64   40  1000000   @
  1   01  0000001 SOH  |  65   41  1000001   A
  2   02  0000010 STX  |  66   42  1000010   B
  3   03  0000011 ETX  |  67   43  1000011   C
  4   04  0000100 EOT  |  68   44  1000100   D
  5   05  0000101 ENQ  |  69   45  1000101   E
  6   06  0000110 ACK  |  70   46  1000110   F
  7   07  0000111 BEL  |  71   47  1000111   G
  8   08  0001000  BS  |  72   48  1001000   H
  9   09  0001001  HT  |  73   49  1001001   I
 10   0A  0001010  LF  |  74   4A  1001010   J
 11   0B  0001011  VT  |  75   4B  1001011   K
 12   0C  0001100  FF  |  76   4C  1001100   L
 13   0D  0001101  CR  |  77   4D  1001101   M
 14   0E  0001110  SO  |  78   4E  1001110   N
 15   0F  0001111  SI  |  79   4F  1001111   O
 16   10  0010000 DLE  |  80   50  1010000   P
 17   11  0010001 DC1  |  81   51  1010001   Q
 18   12  0010010 DC2  |  82   52  1010010   R
 19   13  0010011 DC3  |  83   53  1010011   S
 20   14  0010100 DC4  |  84   54  1010100   T
 21   15  0010101 NAK  |  85   55  1010101   U
 22   16  0010110 SYN  |  86   56  1010110   V
 23   17  0010111 ETB  |  87   57  1010111   W
 24   18  0011000 CAN  |  88   58  1011000   X
 25   19  0011001  EM  |  89   59  1011001   Y
 26   1A  0011010 SUB  |  90   5A  1011010   Z
 27   1B  0011011 ESC  |  91   5B  1011011   [
 28   1C  0011100  FS  |  92   5C  1011100   \
 29   1D  0011101  GS  |  93   5D  1011101   ]
 30   1E  0011110  RS  |  94   5E  1011110   ^
 31   1F  0011111  US  |  95   5F  1011111   _
 32   20  0100000 Space|  96   60  1100000   `
 33   21  0100001   !  |  97   61  1100001   a
 34   22  0100010   "  |  98   62  1100010   b
 35   23  0100011   #  |  99   63  1100011   c
 36   24  0100100   $  | 100   64  1100100   d
 37   25  0100101   %  | 101   65  1100101   e
 38   26  0100110   &  | 102   66  1100110   f
 39   27  0100111   '  | 103   67  1100111   g
 40   28  0101000   (  | 104   68  1101000   h
 41   29  0101001   )  | 105   69  1101001   i
 42   2A  0101010   *  | 106   6A  1101010   j
 43   2B  0101011   +  | 107   6B  1101011   k
 44   2C  0101100   ,  | 108   6C  1101100   l
 45   2D  0101101   -  | 109   6D  1101101   m
 46   2E  0101110   .  | 110   6E  1101110   n
 47   2F  0101111   /  | 111   6F  1101111   o
 48   30  0110000   0  | 112   70  1110000   p
 49   31  0110001   1  | 113   71  1110001   q
 50   32  0110010   2  | 114   72  1110010   r
 51   33  0110011   3  | 115   73  1110011   s
 52   34  0110100   4  | 116   74  1110100   t
 53   35  0110101   5  | 117   75  1110101   u
 54   36  0110110   6  | 118   76  1110110   v
 55   37  0110111   7  | 119   77  1110111   w
 56   38  0111000   8  | 120   78  1111000   x
 57   39  0111001   9  | 121   79  1111001   y
 58   3A  0111010   :  | 122   7A  1111010   z
 59   3B  0111011   ;  | 123   7B  1111011   {
 60   3C  0111100   <  | 124   7C  1111100   |
 61   3D  0111101   =  | 125   7D  1111101   }
 62   3E  0111110   >  | 126   7E  1111110   ~
 63   3F  0111111   ?  | 127   7F  1111111  DEL
  • Dec" は10進数 (Decimal) を、

  • "Hex" は16進数 (Hexadecimal) を、

  • "Bin" は2進数 (Binary) を、

  • "Char" はそのコードに対応する文字 (Character) を示します。

表の "NUL" や "SOH" などの項目は制御文字

ASCIIはテキストファイルやメール、プログラミング言語など、基本的な英文のテキスト処理において今でも広く使われています。しかし、ASCIIは英語と一部の西ヨーロッパ言語にしか対応していないため、多言語対応が必要な場合はUnicodeのようなより包括的な文字コード体系が使用されます。

制御文字

ASCIIの制御文字は、十進数で0から31までの範囲の32個の制御コードがあります。加えて、ASCIIコードの127(十進数)も制御文字であり、DEL(Delete)と呼ばれています。したがって、制御文字の範囲は十進数で0から31まで、そして127が含まれます。

現代のプログラムでは、これらの制御文字を発見したらif文なりで特定の処理と対応させて使用します。

ASCIIの制御文字は、主にテキストの流れを制御するために使われる非表示の文字で、以下の通りです(カッコ内は一般的な略称または説明です):

  • 00 - NUL (Null)

  • 01 - SOH (Start of Header)

  • 02 - STX (Start of Text)

  • 03 - ETX (End of Text)

  • 04 - EOT (End of Transmission)

  • 05 - ENQ (Enquiry)

  • 06 - ACK (Acknowledge)

  • 07 - BEL (Bell)

  • 08 - BS (Backspace)

  • 09 - HT (Horizontal Tab)

  • 0A - LF (Line Feed)

  • 0B - VT (Vertical Tab)

  • 0C - FF (Form Feed)

  • 0D - CR (Carriage Return)

  • 0E - SO (Shift Out)

  • 0F - SI (Shift In)

  • 10 - DLE (Data Link Escape)

  • 11 - DC1 (Device Control 1, often XON)

  • 12 - DC2 (Device Control 2)

  • 13 - DC3 (Device Control 3, often XOFF)

  • 14 - DC4 (Device Control 4)

  • 15 - NAK (Negative Acknowledge)

  • 16 - SYN (Synchronous Idle)

  • 17 - ETB (End of Transmission Block)

  • 18 - CAN (Cancel)

  • 19 - EM (End of Medium)

  • 1A - SUB (Substitute)

  • 1B - ESC (Escape)

  • 1C - FS (File Separator)

  • 1D - GS (Group Separator)

  • 1E - RS (Record Separator)

  • 1F - US (Unit Separator)

これらの制御文字は、コンピュータや通信機器で使用され、文字やデータストリームの解釈に影響を与える目的で設計されました。例えば、改行やタブ、テキストの開始・終了を示すために使用されます。

以下の文類は一般的なガイドラインであり、特定の環境やシステムでは異なる場合があります。

今でも使うもの

  • NUL (Null, 0): 文字列の終端を示すのにC言語などで使われる。

  • BEL (Bell, 7): システムがビープ音を出すためにまれに使用される。

  • BS (Backspace, 8): テキストを消去するために使用される。

  • HT (Horizontal Tab, 9): タブを入力するために使われる。

  • LF (Line Feed, 10): UNIX系OSでの改行に使われる。

  • CR (Carriage Return, 13): Mac OS(9以前)での改行、またWindowsではLFと組み合わせて改行(CRLF)に使われる。

  • ESC (Escape, 27): エスケープシーケンスの開始を示すために使われる。

今では全く使わないもの、使用できないもの

  • SOH (Start of Header, 1),
    STX (Start of Text, 2),
    ETX (End of Text, 3),
    EOT (End of Transmission, 4),
    ENQ (Enquiry, 5),
    ACK (Acknowledge, 6):
    これらは旧来のテレタイプや通信制御に使われていたが、現在の通信プロトコルでは使用されない。

  • SI (Shift In, 15),
    SO (Shift Out, 14):
    かつては文字セットを切り替えるために使われていたが、現在ではほとんど使われていない。

  • DLE (Data Link Escape, 16),
    DC1-DC4 (Device Control 1-4, 17-20),
    NAK (Negative Acknowledge, 21),
    SYN (Synchronous Idle, 22),
    ETB (End of Transmission Block, 23):
    古い通信プロトコルやデバイス制御に使われていたが、現代では使われない。

  • CAN (Cancel, 24),
    EM (End of Medium, 25),
    SUB (Substitute, 26):
    特定の古いシステムでエラー制御やメディアの終わりを示すのに使われていたが、今日では使用されていない。

  • FS (File Separator, 28)
    GS (Group Separator, 29)
    RS (Record Separator, 30)
    US (Unit Separator, 31)
    :
    現代のテキスト処理では一般的ではありませんが、特定のシステムやアプリケーションでは、レコードやデータの区分けとして使われることがあります。特にプログラム内部やデータ交換のプロトコルで、意味のあるセパレータとして使われることがあります。

状況によっては使うもの

  • VT (Vertical Tab, 11),
    FF (Form Feed, 12):
    かつてはプリンターでページの制御に使われたが、現在ではほとんど使われていない。一部のテキストエディタや開発環境では特定の意味で使用する場合がある。

  • DEL (Delete, 127):
    いくつかのテキストエディターやコマンドラインインターフェースで現在も使われている。

これらの制御文字のいくつかは、特定のプロトコルや古いシステム、またはエミュレーター内でのみ意味を持ち、現代の一般的なユーザーアプリケーションやシステムでの使用は減っています。また、新しい通信プロトコルやフォーマットが登場するにつれて、これらの文字の使用頻度はさらに減

UTF-8

UTF-8(8ビット UCS/Unicode変換形式)は、Unicode文字集合をエンコードするための可変長文字エンコーディングの一つです。Unicodeは、世界中のほとんど全ての文字体系を数値化し、コンピュータ上で使用するための業界標準です。

UTF-8の主な特徴は以下の通りです:

  1. 可変長エンコーディング: UTF-8は、1バイトから4バイトまでの可変長のバイト列を使用して任意のUnicode文字を表現します。例えば、ASCII文字は1バイト(8ビット)で表現され、多くのラテン文字やその他の記号も同様ですが、他の多くの文字(例えば、アジアの文字や絵文字)は2バイト以上を必要とします。

  2. バックワード互換性: UTF-8は、従来のASCII文字セットと完全に互換性があります。つまり、ASCIIテキストファイルはUTF-8としても有効です。

  3. 自己同期: UTF-8のエンコーディングは、バイト間の関係が定められているため、データストリームの任意の位置から文字の開始点を見つけることができます。これは、データ損失が発生した場合に次の有効な文字から復旧しやすいという利点があります。

  4. 効率的なデータ処理: 多くのコンピュータシステムやプログラミング環境で使用されているASCII文字だけを扱う場合、UTF-8は追加のオーバーヘッドなしでそのまま使うことができます。

  5. 広範囲の採用: UTF-8はインターネット上で最も広く使用されているエンコーディングであり、WebページやEメールでの標準として広く採用されています。

UTF-8のエンコーディングの仕組みは、1バイト目にその後に続くバイト数を示すリードバイトが使用され、そのバイト内の連続する1の数がその文字のために使われるバイト数を示します。たとえば、リードバイトが`110xxxxx`であれば2バイトの文字であり、`1110xxxx`であれば3バイトの文字、`11110xxx`であれば4バイトの文字です。

UTF-8は、これらの特徴により、世界中の多様な言語をサポートするアプリケーションやシステムにとって理想的な選択肢となっています。

リードバイト

UTF-8エンコーディングにおけるリードバイト(先頭バイト)のパターンは、以下のようになります。これは、各バイトの最初のビットがどのように設定されるかを示しており、エンコーディングされる文字によって異なるバイト数を使用することを示しています。

1バイト文字(ASCII互換)

  • 0xxxxxxx

    • 最初のビットが0の場合、これは1バイト文字で、ASCII文字と直接互換性があります。

2バイト文字

  • 110xxxxx 10xxxxxx

    • 最初のバイトが「110」で始まり、次のバイトが「10」で始まります。

3バイト文字

  • 1110xxxx 10xxxxxx 10xxxxxx

    • 最初のバイトが「1110」で始まり、次の2バイトがそれぞれ「10」で始まります。

4バイト文字

  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

    • 最初のバイトが「11110」で始まり、次の3バイトがそれぞれ「10」で始まります。

ここで「x」は、エンコードされる実際のUnicode文字に応じて設定されるビット(0または1)です。

UTF-8では、2バイト以上の文字をエンコードする場合、リードバイトに続く各バイトは「10」で始まる必要があります。これにより、エンコーダーとデコーダーはどこで新しい文字が始まるかを正確に知ることができます。例えば、途中からでもデータストリームに参加しても、最初に「0」または「110」「1110」「11110」で始まるバイトを探すことで、正しい文字境界を見つけることができます。

リードバイトが見つかったのに、後続のバイトが10でない場合は異常事態です。continuation byte error的なものが出たらこれです。

使用される文字の総数

UTF-8はUnicode文字セットをエンコードするために使用されます。Unicode自体は、現在(私の最後の知識更新時点である2023年4月までの情報に基づく)約14万文字をエンコードすることができ、世界中のほぼすべての文字体系をカバーしています。ただし、Unicodeのバージョンによってサポートされる文字の総数は異なる場合があります。

具体的な数値を挙げると、Unicodeの最新バージョンである13.0においては、以下のような文字数が割り当てられています:

  • 基本多言語面(BMP): 約6万文字。これには、多くの現代言語の文字、記号、絵文字などが含まれます。

  • 補助面(SMP、SIP、TIP、SSPなど): 約8万文字以上。これには、歴史的な文字、追加の絵文字、多くの記号、専門的な記号などが含まれます。

UTF-8はこれらすべての文字をエンコードするために使用され、1バイトから4バイトの範囲で各文字をエンコードします。UTF-8では、Unicodeの全範囲(U+0000 から U+10FFFF)の文字をエンコードすることができますが、現在使われていないコードポイントも多く存在します。ですので、使用される「文字」の総数とは、Unicodeで定義され利用可能な文字の総数を指します。これは、Unicodeのバージョンによって増加しています。

格納限界

理論上、4バイトは実際に32ビットに相当し、したがって(2^{32})、つまり4,294,967,296(約43億)の異なる値を表現する能力があります。しかし、UTF-8で使用される4バイト文字においては、すべての32ビットが自由に使用されるわけではありません。

UTF-8の4バイトの文字では、最初のバイトが`11110xxx`、残りの3バイトがそれぞれ`10xxxxxx`という形式であるため、それぞれのバイトの最初の数ビットは固定されています。これらの固定ビットを除外すると、実際には各バイトで使用できるビットは以下の通りです:

  • 最初のバイト: 3ビットが利用可能(`11110xxx`)

  • 残りのバイト: 各6ビットが利用可能(`10xxxxxx`)

そのため、4バイトの文字の場合、利用可能なビットは合計で21ビットです(3ビット + 6ビット + 6ビット + 6ビット)。したがって、表現可能な異なる値の総数は(2^{21})、つまり2,097,152(約210万)です。

また、UTF-8はUnicodeのコードポイント範囲を尊重するため、実際にはU+0000からU+10FFFFの範囲に制限されます。これは1,114,112(約111万)の可能なコードポイントを意味し、これがUTF-8とUnicodeで表現可能な最大の異なる文字数です。なお、この範囲には、高いサロゲートと低いサロゲートで使用されるコードポイント(U+D800からU+DFFF)が含まれており、これらはUTF-8では使用されません。

UTF-16

unicodeはもともと0 から 65,535の範囲で世界中の全ての文字を当てはめようと画策したが、途中で足らないことに気づいた。なので使ってない真ん中らへんを組み合わせて使うようにした。それをサロゲートペアという。
そのためUTF-16は2byteと4byteが混在する。

UTF-16(Unicode Transformation Format - 16-bit)は、Unicode文字を符号化するための一般的な方式の一つです。Unicodeは、世界中のほぼすべての文字を一貫した方法で符号化することを目的とした国際的な符号化規格です。UTF-16は、それぞれの文字を一つまたは二つの16ビットの単位(合計で16ビットまたは32ビット)で表現します。

UTF-16の特徴

  1. 変動長エンコーディング: UTF-16は変動長エンコーディング方式を採用しています。つまり、使用する文字によっては、文字を表現するのに必要なビット数が変わります。

  2. BMP (Basic Multilingual Plane): 最も一般的に使われる約6万文字は、BMPに属しており、これらの文字は1つの16ビット単位(2バイト)で表されます。

  3. サロゲートペア: BMP外の追加の文字は、2つの16ビット単位を組み合わせたサロゲートペアを使用して表されます。このため、UTF-16でエンコードされたテキストは、文字によっては2バイトの倍数である4バイトを消費することになります。

  4. エンディアン: UTF-16にはエンディアンの概念があります。これは、バイトの順序を意味します。UTF-16では、Big Endian(BE)とLittle Endian(LE)の両方の形式が存在し、バイト順序マーク(BOM)が使用されることがあり、ファイルやデータストリームの先頭に置かれてエンディアンを示します。

基本多言語面(BMP)とサロゲートペアの範囲

Unicodeの基本多言語面(BMP)とサロゲートペアの範囲は以下のようになります。

BMP(基本多言語面)の範囲:

  • 16進数: 0x0000 から 0xFFFF

  • 10進数: 0 から 65,535

サロゲートペアの範囲は、上位サロゲート(high surrogates)と下位サロゲート(low surrogates)に分かれます。

上位サロゲート(High Surrogates)の範囲:

  • 16進数: 0xD800 から 0xDBFF

  • 10進数: 55,296 から 56,319

下位サロゲート(Low Surrogates)の範囲:

  • 16進数: 0xDC00 から 0xDFFF

  • 10進数: 56,320 から 57,343

これらの範囲は、BMPの外側に位置する追加の文字セット(補助多言語面と補助特殊用途面を含む)をエンコードするために予約されています。UTF-16エンコーディングでは、これらの範囲のコードポイントを使用して、BMPを超える1,048,576((16^4))の追加コードポイントにアクセスできるようになっています。

UTF-32

UTF-32は、Unicode文字を表現するための符号化方式の一つです。UTFは「Unicode Transformation Format」の略で、32は各Unicode文字を表すのに32ビット(4バイト)を使用することを意味します。

UTF-32の特徴は以下の通りです:

  1. 固定長符号化:
    UTF-32は、全ての文字を等しいサイズのコード単位でエンコードします。各Unicode文字は厳密に4バイトで表されます。

  2. 直接アクセス:
    固定長のため、テキストの任意の位置にある文字へのランダムアクセスが容易になります。つまり、n番目の文字を取得するために前の文字を調べる必要がありません。

  3. シンプルなエンコーディング:
    文字コードの変換が他の多くのエンコーディング方式(例:UTF-8やUTF-16)と比較して単純であり、エンコーディングとデコーディングが速く実行できます。

  4. メモリ使用量が大きい:
    すべての文字を4バイトで表すため、UTF-8やUTF-16に比べてメモリの消費が大きいです。特に、ASCIIテキストでは他のエンコーディング方式よりも大幅に効率が落ちます。

  5. 互換性:
    Unicodeのすべての文字を直接エンコードできるため、サロゲートペアのような追加的なエンコーディング機構を必要としません。これはUTF-16では必要なサロゲートペアを使う代わりに、UTF-32では1つのUnicodeコードポイントが直接一つの32ビット値にマップされます。

UTF-32はUnicodeの範囲(0から0x10FFFF)を全て直接カバーしているため、Unicode標準に新しい文字が追加されたとしても、UTF-32は既にそれらを表現するためのスペースを持っています。しかし、この容量の大きさが、データの転送や保存において効率が悪いという欠点にもなります。

一般的な使用例では、テキストデータを処理する内部システムでUTF-32が使われることがありますが、ネットワーク経由でテキストデータを送信する場合や、ストレージにテキストデータを保存する場合には、より効率的なUTF-8やUTF-16が一般的に使われます。

BOM

BOM(Byte Order Mark)は、テキストファイルがどのエンコーディングで記述されているかを示すために使われる特別な文字コードのシーケンスです。特に、Unicodeテキストを保存する際に使用されることが多いです。

Unicodeには、同じ文字を表現するために複数のエンコーディング方式(UTF-8, UTF-16, UTF-32など)があり、これらの中で、UTF-16とUTF-32にはエンディアン(バイト順)の違いがあります。エンディアンとは、メモリー内でバイトが並ぶ順番のことで、主にビッグエンディアン(Big Endian)とリトルエンディアン(Little Endian)の2種類があります。

BOMはこのエンディアンの違いを区別するために使用されます。例えば、UTF-16では、ビッグエンディアンを使う場合はファイルの先頭にFEFFというコードを、リトルエンディアンを使う場合はFFFEというコードを付けます(実際のファイルではこれらはバイトとして表現されます)。このコードがあることで、ソフトウェアはどのエンディアンでデータが記述されているかを判断できます。

ただし、UTF-8ではエンディアンの概念がありませんが、BOMを使用してテキストがUTF-8でエンコードされていることを示すことができます。UTF-8のBOMはEFBBBFというシーケンスです。

BOMの使用は必ずしも必要ではありませんが、特に複数の異なるシステム間でファイルが共有される場合には、正しいエンコーディングでファイルが解釈されることを保証するために便利です。しかし、BOMがない場合も多く、ソフトウェアが自動的にエンコーディングを検出することが期待されることが一般的です。

BOMの存在は、場合によっては問題を引き起こす可能性もあります。例えば、UTF-8エンコードされたファイルでBOMが不要な場合(Unix系のシステムでスクリプトの先頭にある場合など)、それが誤って解釈されてしまうことがあります。そのため、使用するシステムやソフトウェアがBOMに対応しているかどうかを把握し、適切に対応する必要があります。

コード

まだ途中。

C

ASCII

#include <stdio.h>

int main() {
    // ファイルを開く。書き込みモードで開く
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        perror("ファイルを開けませんでした");
        return 1;
    }

    // ASCII文字列をファイルに書き込む
    char str[] = "Hello, World!";
    fputs(str, file);

    // ファイルを閉じる
    fclose(file);

    return 0;
}

UTF-8

C言語でUnicodeを扱うためには、外部のライブラリを利用することが一般的です。幾つかの有名なライブラリがありますが、それぞれに特徴がありますので、プロジェクトの要件に合わせて選択すると良いでしょう。

ICU (International Components for Unicode) ICUは非常に強力で広範に渡るUnicodeサポートを提供するC/C++ライブラリです。文字列操作、日付フォーマット、数値フォーマット、文字セット変換、Unicode正規化、コラテーション(文字列の比較)、言語感知的な検索、および正規表現など、幅広い機能を提供します。非常に安定しており、業界標準として広く使われています。

libunistring libunistringは、Unicode文字列を扱うためのCライブラリで、Unicode文字の処理、文字列の変換、正規化、ケース変換、言語特有の操作などの機能を提供します。libunistringは、GNUプロジェクトによってサポートされており、フリーでオープンソースのライブラリです。

utf8proc utf8procは、UTF-8エンコーディングを使用するためのCライブラリで、Unicodeの正規化、ケースフォールディング、その他の操作を簡単に行うことができます。比較的軽量でありながら、必要なUnicode機能を備えています。

これらのライブラリは、様々なUnicode関連の機能を提供しており、多くの場合で安定した動作を期待できます。プロジェクトのニーズに応じて、これらのライブラリの中から選択すると良いでしょう。また、これらのライブラリはオープンソースであるため、使用にあたってのライセンス条件を確認することを忘れないでください。

C言語の標準ライブラリには直接的なエンコーディングのサポートはありません。UTF-8としてエンコードされたファイルの読み書きは、バイト単位で行う必要があります。

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *file;
    char buffer[1024];

    // ファイルを読み込む
    file = fopen("input.txt", "r");
    if (file == NULL) {
        perror("ファイルを開けません");
        return EXIT_FAILURE;
    }
    while (fgets(buffer, sizeof(buffer), file)) {
        printf("%s", buffer);
    }
    fclose(file);

    // ファイルを書き込む
    file = fopen("output.txt", "w");
    if (file == NULL) {
        perror("ファイルを開けません");
        return EXIT_FAILURE;
    }
    fputs("これはテストです。\n", file);
    fclose(file);

    return 0;
}

ICU (International Components for Unicode)

#include <stdio.h>
#include <unicode/ucnv.h>
#include <unicode/ustring.h>

int main(void) {
    UErrorCode status = U_ZERO_ERROR;
    UConverter *conv = ucnv_open("UTF-8", &status);
    if (U_FAILURE(status)) {
        printf("Cannot open converter\n");
        return 1;
    }

    const char src[] = "こんにちは世界"; // UTF-8
    UChar dest[256];
    int32_t dest_len;

    // UTF-8 to UTF-16
    u_strFromUTF8(dest, 256, &dest_len, src, -1, &status);
    if (U_FAILURE(status)) {
        printf("Cannot convert to UTF-16\n");
    } else {
        printf("Converted to UTF-16\n");
    }

    ucnv_close(conv);
    return 0;
}

libunistring

#include <stdio.h>
#include <unistr.h>
#include <unicase.h>
#include <uninorm.h>

int main() {
    uint8_t utf8_string[] = "こんにちは世界";
    uint32_t utf32_string[256];
    size_t len = 0;

    // UTF-8 to UTF-32
    u8_to_u32(utf8_string, sizeof(utf8_string), utf32_string, &len);

    // 正規化
    uint32_t normalized[256];
    size_t normalized_len = u32_normalize(UNINORM_NFC, utf32_string, len, normalized, 256, NULL);

    if (normalized_len > 0) {
        printf("Normalized string\n");
    } else {
        printf("Normalization failed\n");
    }

    return 0;
}

utf8proc

#include <stdio.h>
#include <utf8proc.h>

int main() {
    const utf8proc_uint8_t *str = (const utf8proc_uint8_t *)"こんにちは世界";
    utf8proc_ssize_t result_len;
    utf8proc_uint8_t *result;

    // UTF-8文字列をNFC形式に正規化する
    result = utf8proc_NFC(str, utf8proc_strlen(str), &result_len);
    if (result) {
        printf("Normalized string: %s\n", result);
        free(result);
    } else {
        printf("Normalization failed\n");
    }

    return 0;
}

C++

ASCII

#include <iostream>
#include <string>

int main() {
    std::string str = "Hello, World!"; // ASCII string
    // バイナリファイルとして保存する例
    std::ofstream outfile("example.txt", std::ofstream::binary);
    outfile.write(str.c_str(), str.size());
    outfile.close();
    return 0;
}

UTF-8
C++では、入出力ストリームクラスを使用して、UTF-8テキストファイルを扱うことができます。C++11以降、<fstream>を使用したファイル入出力は基本的にUTF-8をサポートしています。

#include <fstream>
#include <iostream>
#include <string>

int main() {
    std::ifstream input("input.txt");
    std::string line;

    // ファイルを読み込む
    if (input.is_open()) {
        while (getline(input, line)) {
            std::cout << line << std::endl;
        }
        input.close();
    }

    // ファイルを書き込む
    std::ofstream output("output.txt");
    if (output.is_open()) {
        output << "これはテストです。\n";
        output.close();
    }

    return 0;
}

C#

ASCII

using System;
using System.IO;
using System.Text;

class Program {
    static void Main() {
        string unicodeString = "Hello, World!";
        // Unicode文字列をASCIIバイト配列に変換する
        byte[] asciiBytes = Encoding.ASCII.GetBytes(unicodeString);

        // ファイルにASCIIとして保存
        File.WriteAllBytes("example.txt", asciiBytes);
    }
}

UTF-8

using System;
using System.IO;
using System.Text;

class Program {
    static void Main() {
        string path = "input.txt";

        // ファイルを読み込む
        string readText = File.ReadAllText(path, Encoding.UTF8);
        Console.WriteLine(readText);

        // ファイルを書き込む
        path = "output.txt";
        string writeText = "これはテストです。";
        File.WriteAllText(path, writeText, Encoding.UTF8);
    }
}

Java

ASCII

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        String str = "Hello, World!";
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("example.txt"))) {
            writer.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

UTF-8


python

ASCII

# 普通のPythonスクリプトの場合
str = "Hello, World!"
with open("example.txt", "w") as f:
    f.write(str)

# Google Colabの場合、同じPythonコードを使えますが、
# ファイルシステムが異なるため、左側のファイルタブからファイルを確認できます。

Google Colab

ASCII

仮想マシンに保存(セッションが終了するとファイルは失われる):

# このコードはColabノートブック内で直接実行します
with open('example.txt', 'w') as f:
    f.write('Hello, World!')

Google ドライブに保存(永続的にファイルを保持):

# このコードはColabノートブック内で直接実行します
from google.colab import drive
drive.mount('/content/drive')

# 保存するファイルのパスを指定します。必要に応じてパスを変更してください。
file_path = '/content/drive/My Drive/example.txt'

with open(file_path, 'w') as f:
    f.write('Hello, World!')

自分のPCに保存(ブラウザを通してダウンロード):


# このコードはColabノートブック内で直接実行します
from google.colab import files

with open('example.txt', 'w') as f:
    f.write('Hello, World!')

# ユーザーにダウンロードを促すダイアログを表示します
files.download('example.txt')

JavaScript

ASCII

const fs = require('fs');

let str = "Hello, World!";
fs.writeFile('example.txt', str, 'ascii', function(err) {
    if (err) throw err;
    console.log('The file has been saved!');
});





この記事が気に入ったらサポートをしてみませんか?