HZ

HZ

[5] GB 2312 (と ASCII) で書かれた文字列の符号化方式です。 7ビットで、 ASCII の印字可能図形文字の範囲で中文文字を表現出来ます。 8ビット目や CL の制御文字を落とす通信路を通っても安心です。

Fung Fung Lee によって考案されました。 その定義は後に RFC 1843 『HZ - A Data Format for Exchanging Files of Arbitrarily Mixed Chinese and ASCII characters』として まとめられています。

更に、RFC 1842 『ASCII Printable Characters-Based Chinese Character Encoding for Internet Messages』で再定義されています。

[16] かつては中国大陸電子メールや一部の Webページで用いられていましたが、 現在は GB 18030Unicode に移行しており、過去の文書を読み書きする必要がある特殊な場合を除き、 対応する必要はないと考えられています。

[17] Web における文字コードを規定する Encoding Standard からも2014年11月に削除されています >>11

仕様書

[14] Encoding Standard により近代的な定義がありましたが、削除されています (>>11)。

構造

ASCII の "~" (0x7E; TILDE) をエスケープ文字に使います。

~{GB 2312 HZ モードへ
~}HZ モードから ASCII モードへ
~~ASCII TILDE ("~"; 0x7E)
~\nASCII モード中で、行継続 (軟改行)
~[!-z|]将来の HZ モード文字集合に予約

RFC 1842, 1843 を読むと、 "~{" は ASCII モードにおいて GB 2312 HZ モードへ移行し、 "~}" は GB 2312 HZ モードにおいて ASCII モードに移行するとされてます。また、 GB 2312 文字列は "~{" と "~}" で囲まれる、とされてます。

ですから、 ISO-2022-JP とは違って、 aiueo~}abcde とか ~{123456~{567891~} は不正だと思われます。

BNF

RFC 1842 より。 RFC 822 メッセージでの使用を想定しているので、 こういうことになってます。
   message             = headers 1*( CRLF *single-byte-char *segment
                         single-byte-seq *single-byte-char )
                                       ; see also [MIME1] "body-part"
                                       ; note: must end in ASCII
  1. headers = <see [RFC822] "fields" and [MIME1] "body-part">
  2. segment = single-byte-segment / double-byte-segment
  3. single-byte-segment = 1*single-byte-char
  4. double-byte-segment = double-byte-seq 1*( one-of-94 one-of-94 )
  5. single-byte-seq = "~}"
  6. double-byte-seq = "~{"
  7. CRLF = CR LF
  8. ; ( Octal, Decimal.)
  9. CR = <ASCII CR, carriage return>; ( 15, 13.)
  10. LF = <ASCII LF, linefeed> ; ( 12, 10.)
  11. one-of-94 = <any one of 94 values> ; (41-176, 33.-126.)
   single-byte-char    = <any 7BIT, including bare CR & bare LF, but NOT
                          including CRLF, not including > / "~~">;
  1. 7BIT = <any 7-bit value> ; ( 0-177, 0.-127.)

single-byte-char がなんかおかしいですし、 ~\n が定義に現れてません。

ASCII "~{" GB ASCII "~}" ASCII みたいのでもいいことになってしまいますが、明らかにおかしいです。

GB 2312 の文字の部分が one-of-94 one-of-94 ですから、たとえば "~{" という74区の文字も OK になってしまいます。

GB 2312 文字がない行でも ~} が1つ要るように見えますが、 これは RFC 1468 (ISO-2022-JP) などにもある不具合です。

現代風に再定義してみましょう。

  1. hz = *(hz-line CRLF) hz-line
  2. hz-line = *segment
  3. segment = ascii / gb2312 / special
  4. ascii = %x00-09 / %x0B-0C / %x0E-7D / %x7F
  5. gb2312 = "~{" 1*double-byte-char "~}"
  6. double-byte-char = %x21-7D %x21-7E
  7. special = tilde / soft-linebreak / reserved-sequence
  8. tilde = "~~"
  9. soft-linebreak = "~" CRLF
  10. reserved-sequence = "~" ( %x21-7A / %x7C )

GB 2312 では94区に文字は定義されていませんから、 94区の文字をどう扱うかは規定されていません。

soft-linebreak は、 RFC 1843 では 0x0A とされていますが、 RFC 1842 は RFC 822 で使うことを想定しているので 0x0D 0x0A です。その辺は、改行コード問題を引き摺らざるをえないってことです。

エラー処理

[1] "~{" で GB 2312 mode になったまま改行で、次の行から (そこまで "~}" なしで) ASCII に戻る文書が少なからず あるみたいです。復号する実装は option で行頭において ASCII に戻るように出来るのが良いでしょう。

[2] >>1 GB mode で制御文字が使えるのかどうか、怪しい BNF 的には使えないみたいで、その他の部分でも使えるとは一言も 言ってませんから、行頭で必ず ASCII に戻してしまっても いいかもしれません。

   Example 1:  (Suppose there is no line size limit.)
               This sentence is in ASCII.
               The next sentence is in GB.~{<:Ky2;S{#,NpJ)l6HK!#~}Bye.
   Example 2:  (Suppose the maximum line size is 42.)
               This sentence is in ASCII.
               The next sentence is in GB.~{<:Ky2;S{#,~}~
               ~{NpJ)l6HK!#~}Bye.
   Example 3:  (Suppose a new line is started for every mode switch.)
               This sentence is in ASCII.
               The next sentence is in GB.~
               ~{<:Ky2;S{#,NpJ)l6HK!#~}~
               Bye.

名前と実装

MIME charset

charset 名 "HZ-GB-2312" が RFC 1842 で定義されています。

Perl Encode モジュール

[6] Encode::CN::HZ で "hz" に対応しています。

変種

[15] GB 2312 部分で右半面を使う HZ8 もあります。

メモ

[8] Re: Encoding Standard at F2F ( (신정식 著, 版)) <http://lists.w3.org/Archives/Public/www-international/2012OctDec/0039.html>

[9] Issue 265973003: Implement "replacement" text encoding. - Code Review ( ( 版)) <https://codereview.chromium.org/265973003>

[10] Mark hz-gb-2312 more clearly as nearly removed · 2b017e7 · whatwg/encoding ( ( 版)) <https://github.com/whatwg/encoding/commit/2b017e76a148b74cf5f052db854d4f7c2d2cebd7>

[11] Remove hz-gb-2312 per https://www.w3.org/Bugs/Public/show_bug.cgi?id=253... · 27513da · whatwg/encoding ( 版) <https://github.com/whatwg/encoding/commit/27513dad60cc80270e28d776939746b040b45fd0>

[18] [cssom] Cleanup some serialization bits. (emilio著, ) <https://github.com/w3c/csswg-drafts/commit/5cc9ddd332465b7512befe06dd650754c824645a>