Ada 2020 (28日目) - Is_Basic/To_Basic

文字コード話はネガティブにならざるを得ないのでさっさと終わらせましょうね。

経緯

Ada.Characters.Handling にある Character を扱う関数のうち(ISO_646 こと7ビットASCII関係を除けば) Is_BasicTo_Basic の2つのみ Wide_Character/Wide_Wide_Character 版が存在していませんでした。

Ada 2020での改善

Wide_Character 版にあたる Ada.Wide_Characters.Is_BasicTo_Basic が追加されました。

Ada.Wide_Wide_Characters.HandlingAda.Wide_Characters.Handling 同様と定義されていますので自動的に Wide_Wide_Character 版も追加されることになります。

Ada.Wide_Characters.Is_Basic

Ada.Wide_Characters.Is_Basic は引数の文字が正規分解(canonical decomposition)できるなら False 、それ以上分解できなければ True を返します。

Ada.Wide_Characters.To_Basic

Ada.Wide_Characters.To_Basic は引数の文字が正規分解できるなら分解後の基底文字(base character)を返します。 分解できなければ引数をそのまま返します。

ライブラリの実装が使用しているUnicodeのバージョンは Ada.Wide_Characters.Character_Set_Version で調べることができます。

関連AI

  • AI12-0260-1 Functions Is_Basic and To_Basic in Wide_Characters.Handling

所感

めでたしめでたし、で済ませたいのです。 はい、例によって書いておきたいことが。 ただの個人の日記ですので例によって読むだけ損です。

Ada.Characters.Is_Basic

Ada.Characters っていつから存在していると思います?

Unicodeの最初のバージョンISO/IEC 10646-1:1993が1993年です。 Ada.Characters が追加されたAda 95は勿論1995年。

時期としては近いので微妙なところです。 勿論どちらの規格も制定の何年も前から練られていたわけです。

結論から書いてしまいますとAda 95ではISO 10646のBMPに対応する16ビット文字型の Wide_Character/Wide_String 、ライブラリとしては Ada.Strings 以下の Wide_* 版や Ada.Wide_Text_IO 等が追加されましたが、これらは言わばコンテナで中身については何もありませんでした。

Wide_Character の中身を具体的に扱う Ada.Wide_Characters の登場はAda 2005からです。

そのような時期的な理由で Ada.Characters.Is_Basic はUnicodeを意識した定義にはなっていません。

True if Item is a basic letter. A basic letter is a character that is in one of the ranges ‘A’..’Z’ and ‘a’..’z’, or that is one of the following: ‘Æ’, ‘æ’, ‘Ð’, ‘ð’, ‘Þ’, ‘þ’, or ‘ß’.

というわけで動作を比較しますとこうなるわけです。

引数

Ada.Characters.Is_Basic

Ada.Wide_Characters.Is_Basic

上記の基底文字

True

True

その他基底文字

False

True

合成済み文字

False

False

結合文字

(Latin-1の範囲にはなし)

True

それ以外

False

True

Ada.Characters.Is_Basic は丁度 Ada.Wide_Characters.Is_BasicIs_Letter との論理積を取ったような動作です。

Latin-1の範囲ではアルファベットにしかダイアクリティカルマークは付きませんからこの動作でも良かったですがUnicodeではどんな文字でも合成することができます。 そのため Ada.Characters.Is_Basic と互換をとっても使い物になりません。

しかし別物に同じ名前が付いていますと CharacterWide_Character 両方に対応する generic なコードを書くのに支障が出ます。

generic
   type Character_Type is (<>);
   with function Is_Basic (Item : Character_Type) return Boolean is <>;
package Generic_Something is

みたいなやつです。

当時、別物には別の名前を付けてくれと訴えましたがAIの提案者のJ-P. Rosen先生本人に

If you are adapting a program to use the full BMP instead of Latin1, expect many more difficult issues and/or incompatibilities than this one…

と言われてしまいました……。

Latin-1用のコードをUnicode用に書き換えるならこんな小さな非互換性より大変なことは一杯ある、ということですね……。

幸い To_Basic の方には差はありません。

generic なコードを書くときは To_Basic のみを用いて分解できるかの判定は To_Basic (Item) /= Item とすればいいでしょう。