For Development HEAD DRAFTSearch (procedure/syntax/module):

9.37 gauche.unicode - Unicodeユーティリティ

Module: gauche.unicode

このモジュールは、Unicodeのコードポイントの列に対する様々な操作を提供します。

Gaucheは以前、内部文字エンコーディングとしてUnicode以外も選べるようになっていました。 その場合、文字列に対して完全にUnicode互換の動作を提供できない場合があったため、 そこで、本モジュールの多くの操作は、文字列を対象にするものと、 コードポイントの数値のシーケンスを対象にするものの両方で提供されます。


9.37.1 Unicode transfer encodings

このグループの手続きは、整数で表現されたコードポイントを扱います。 以下の説明で「オクテット」は0から255までの整数です。

これらの手続きは省略可能なstrictness引数を取ります。 この引数は、定義域外の入力が来たときの振る舞いを指定します。 指定できる値は次のいずれかです。

strict

定義域外の入力が来たらエラーを投げます。これがデフォルトの振る舞いです。

permissive

可能な限り、入力を有効な値であるかのように扱います。 例えば#x10ffffを越えるコードポイント値はUnicode標準では不正な値ですが、 utf-8の規則を拡張することでエンコード可能であり、文字列以外のバイナリデータを単にutf-8風に エンコードしたいだけの場合などには便利かもしれません。

replace

不正な入力を見たら、それをユニコード置換文字U+FFFDに置き換え処理を続行します。

ignore

可能であれば、不正な入力は無視します。

strictnesspermissivereplaceignoreであっても、 入力データの妥当な解釈ができない場合はエラーが投げられる可能性があります。

Function: ucs4->utf8 codepoint :optional strictness

{gauche.unicode} 整数のコードポイント値を受け取り、utf-8でエンコードされたオクテットのリストを返します。

(ucs4->utf8 #x3bb)  ⇒ (206 187)
(ucs4->utf8 #x3042) ⇒ (227 129 130)

strictnessstrictの場合(デフォルト)、 入力が#xd800#xdfffの間か、#x110000以上の場合は エラーを投げます。 strictnessreplaceであれば、そのような入力に対しては utf8シーケンス#xef, #xbf, #xbd (U+FFFD) がせ生成されます。 strictnesspermissiveの場合は、 0から#x7fffffffまでの入力が許されます。 入力が大きい場合はエンコードされた出力は5〜6オクテットになるでしょう (初期のutf-8の定義通り)。 strictnessignoreの場合は、 Unicodeとして不正なコードポイントに対しては空リストが返されます。

Function: utf8-length octet :optional strictness

{gauche.unicode} octetをutf-8シーケンスの最初のオクテットとみなし、 そこからひとつのコードポイントをデコードするのに全部で何オクテット必要かを返します。

octet引数が0から255の間の正確な整数でなければ、 strictness引数の値にかかわらず、エラーが投げられます。

strictnessstrictの場合(デフォルト)、 戻り値は1,2,3,4のいずれかです。octetがutf-8でエンコードされた Unicodeコードポイントの最初のオクテットとしてありえない値であれば エラーが投げられます。

strictnesspermissivereplaceの場合、 この手続きは0から6までの整数を返します。 入力が#xf8から#xfdの間の値(両端含む)の場合は 元々のutf-8仕様に基づいて5か6を返します (これらのオクテットはコードポイントが#x110000から #x7fffffffになるような値に相当します)。 引数が#x80から#xbfまでの値、および#xfe#xffの場合は、 utf-8の先頭バイトになり得ませんが、アプリケーションがこの不正なバイトだけを 適切に処理することを前提にして、1が返されます。

strictnessignoreの場合、この手続きは strictでエラーが投げられる入力値について0を返します。 それ以外はstrictの動作と同じです。

Function: utf8->ucs4 octet-list :optional strictness

{gauche.unicode} オクテットのリストを取り、それをutf-8のシーケンスとして解釈して、 デコードされたコードポイント及び残りのリストの2つの値を返します。

もし処理中に、0から255の間の正確な整数以外の値が入力に見つかったら、 strictnessの設定に関わらずエラーが投げられます。

それ以外の不正なutf-8シーケンスは、strictnessstrictであれば エラーに、ignoreであればスキップされます。 strictnessreplaceの場合は、そういったutf8シーケンスは U+FFFDを生成します。 strictnesspermissiveの場合は、 最初のutf-8仕様で許されていた全てのコードポイント、すなわち サロゲートペア領域(#xd800から#dfffまで)及び #x110000以上#x7fffffff以下のコードポイントも認識されます。 それ以外の不正なコードポイントはpermissiveであってもエラーになります。

Function: utf8->string u8vector :optional start end

[R7RS base] {gauche.unicode} u8vectorの、インデックスstart(含む)からend(含まない)までに 格納された値をutf-8オクテット列と見なし、文字列に変換して返します。 startendが省略された場合はそれぞれベクタの最初と最後が指定されたものと 解釈します。

Gaucheのネイティブエンコーディングがutf8の場合、 この手続きはまずu8vector->stringを試します (ユニフォームベクタ参照)。 もし入力がutf8シーケンスとして有効であれば、それが最も速いです。 しかし、入力に無効なutf8シーケンスが含まれていた場合、 この手続きは1文字づつ文字列を構築するモードにフォールバックし、 無効なutf8シーケンスの部分はUnicode置換文字U+FFFDに置き換えられます。 従って戻り値は常に完全な文字列です。 入力に不正なuft8シーケンスが含まれていたかどうかを知りたい場合は u8vector->stringを直接呼んでください。

Gaucheのネイティブエンコーディングがutf8以外の場合、 U+FFFDに相当するコードがないので、無効なutf8シーケンスに出会うと エラーが投げられます。

Function: string->utf8 string :optional start end

[R7RS base] {gauche.unicode} 文字列をutf8オクテットの並びにエンコードしてu8vectorとして返します。 省略可能なstartend引数は対象とする文字列の範囲を指定します。

Gaucheのネイティブエンコーディングがutf8であれば、この手続きは 単にstring->u8vectorを呼び出すだけです。 (ユニフォームベクタ参照)。 そうでなければまず入力文字列がutf8に変換されてから string->u8vectorが呼ばれます。

Function: ucs4->utf16 codepoint :optional strictness

{gauche.unicode} 整数で与えられたコードポイントをutf-16にエンコードして整数のリストとして返します。

strictnessstrictの場合(デフォルト)、 入力値は0から#xd7ffまでの間か、 #xe000から#x10ffffまでの間でなければなりません。 それ以外の場合はエラーが投げられます。 開いている部分はサロゲートに予約されているコードで、 この領域をutf-16にエンコードする方法は定義されていません。

strictnessreplaceであれば、そのような入力は #xfffd(Unicode置換文字)に置き換えられます。

strictnesspermissiveの場合、サロゲート領域の入力は エラーにならず、その値を唯一の要素とするリストが返されます。 負の値および#x110000の値についてはやはりエラーになります。

strictnessignoreの場合は、不正なコードポイント(サロゲート領域含む) については空リストが返されます。

註: permissiveモードでは#x10ffffより大きな値をutf-8にはエンコードできますが、 utf-16にはエンコードできません。

Function: utf16-length code :optional strictness

{gauche.unicode} codeは0から65535までの正確な整数でなければなりません。 codeがBMPのコードポイントなら1を、utf-16の上位サロゲートであれば2を返します。

strictnessstrictの場合(デフォルト)、codeが 下位サロゲートであったり、定義外の値であればエラーが投げられます。 strictnesspermissivereplaceの場合は、 やはり定義外の値であればエラーが投げられますが、 下位サロゲートの場合には1が返されます。 strictnessignoreの場合、 定義域外および下位サロゲートに対しては0が返されます。

Function: utf16->ucs4 code-list :optional strictness

{gauche.unicode} 正確な整数のリストを取り、それをutf-16の並びとして解釈します。 デコードされたucs4コードポイントおよび、残りのリストの二つの値を返します。

strictnessstrictの場合(デフォルト)、不正なutf-16の並びや 定義域外の値に出会ったらエラーが投げられます。 strictnesspermissiveの場合は、 やはり定義外の値であればエラーが投げられますが、 片方だけのサロゲートの場合にはそれがそのまま(コードポイントとして)返されます。 strictnessreplaceの場合は、 片方だけのサロゲートはU+FFFDに置換されます。 strictnessignoreの場合、 定義域外および片方だけのサロゲートは無視されます。

Function: utf16->string u8vector :optional endian ignore-bom? start end
Function: utf32->string u8vector :optional endian ignore-bom? start end

{guache.unicode} [R7RS scheme.bytevector] u8vectorに格納されたutf16およびutf32シーケンスを文字列に変換します。 utf16->stringは、 もし入力に不正なutf16シーケンス (ペアになっていないサロゲート) があった場合は、 それがUnicode置換文字(U+FFFD)に置き換えます。 入力のオクテット数がエンコーディング単位(utf16なら2オクテット、utf32なら4オクテット) の倍数でない場合はエラーが投げられます。

省略可能なendianignore-bom?引数は入力がUTF16BE/UTF32BEか UTF16LE/UTF32LEかを 決めます。ignore-bom?#fまたは省略された場合、まず入力の 最初の2オクテットが調べられ、BOMであればendianの値にかかわらず それがバイトオーダーを決定します。 入力がBOMで始まっていないか、ignore-bom?が真の値であれば、 endian引数がバイトオーダーを決定します。それが big-endianbigであればUTF16BE/UTF32BE、 little-endianlittlearm-little-endianであれば UTF16LE/UTF32LEとなります (エンディアンについてはエンディアンネス参照)。

ignore-bom?が与えられて真の値であった場合、 入力の先頭のBOMはコードポイントとみなされます。 endian#fまたは省略された場合は、 UTF16BE/UTF32BEとみなされます (これはR7RS scheme.bytevectorで定義された仕様です)。

なおR7RS scheme.bytevectorではignore-bom?引数は endianness-mandatoryと呼ばれています。動作は同じです。

省略可能なstartend引数は処理に先立って入力のオクテットシーケンスの 範囲を制限します(BOM検出も範囲制限後に行われます)。 この2つの引数はGauche独自拡張で、R7RS scheme.bytevectorでは定義されていません。

Function: string->utf16 str :optional endian add-bom? start end
Function: string->utf32 str :optional endian add-bom? start end

{gauche.unicode} [R7RS scheme.bytevector] 文字列strをutf-16またはutf-32にエンコードしたオクテット列をu8vectorで返します。

省略可能なendian引数は、エンコーディングがUTF16BE/UTF32BEかUTF16LE/UTF32LEかを決めます。 シンボルbig-endianbigが渡されたらUTF16BE/UTF32BE、 シンボルlittle-endianlittlearm-little-endianが 渡されたらUTF16LE/UTF32LEになります。省略されるか#fならUTF16BE/UTF32BEになります。 バイトオーダーについての詳細はエンディアンネスを参照してください。

二つめの省略可能引数add-bom?にもし真の値が与えられたら、 出力の先頭にBOMが含められます。省略されるか#fであればBOMは付加されません。

続く省略可能引数startendは入力文字列strの特定の範囲だけを 対象とするのに使います。

R7RSのscheme.bytevectorではendian引数だけを認めています。 残りはGaucheの拡張です。


9.37.2 Unicode text segmentation

These procedures implements grapheme-cluster and word breaking algorithms defined in UAX #29: Unicode Text Segmentation.

Function: string->words string
Function: codepoints->words sequence

{gauche.unicode} 与えられた文字列あるいはコードポイントシーケンス(コードポイントを要素とする <sequence>オブジェクト)から、単語のリストを返します。 各単語はそれぞれ、文字列あるいはコードポイントシーケンスで表現されます。

(string->words "That's it.")
 ⇒ ("That's" " " "it" ".")
(codepoints->words '(84 104 97 116 39 115 32 105 116 46)
 ⇒ ((84 104 97 116 39 115) (32) (105 116) (46))
(codepoints->words '#(84 104 97 116 39 115 32 105 116 46)
 ⇒ (#(84 104 97 116 39 115) #(32) #(105 116) #(46))

二番めと三番目の例の入力は "That’s it." をコードポイント列にしたものです。

Function: string->grapheme-clusters string
Function: codepoints->grapheme-clusters sequence

{gauche.unicode} 与えられた文字列あるいはコードポイントシーケンス(コードポイントを要素とする <sequence>オブジェクト)から、graphemeクラスタのリストを返します。 各クラスタはそれぞれ、文字列あるいはコードポイントシーケンスで表現されます。

以下の手続きは上記のstring->words等の高レベル手続きを作る部品となる、 低レベル手続きです。

Function: make-word-breaker generator
Function: make-grapheme-cluster-breaker generator

{gauche.unicode} 文字かコードポイントを生成するジェネレータgeneratorを取り、 二つの値を返すジェネレータを返します。最初の値は元のジェネレータから受け取った 文字またはコードポイントで、二つめの値は、その文字またはコードポイントの直前に 単語もしくはgraphemeクラスタ境界があった時に#t、そうでない時に#fとなる 真偽値です。

ジェネレータgが文字列That's it.に含まれる文字を順に返す ジェネレータとすれば、作られるジェネレータの動作は次の通りです。

(define brk (make-word-breaker g))
(brk)  ⇒  #\T     and #t
(brk)  ⇒  #\h     and #f
(brk)  ⇒  #\a     and #f
(brk)  ⇒  #\t     and #f
(brk)  ⇒  #\'     and #f
(brk)  ⇒  #\s     and #f
(brk)  ⇒  #\space and #t
(brk)  ⇒  #\i     and #t
(brk)  ⇒  #\t     and #f
(brk)  ⇒  #\.     and #t
(brk)  ⇒  #<eof>  and #t

つまり、下図で^で示される箇所が単語境界となっています (空白字を_で表しています)。

  T h a t ' s _ i t .
 ^           ^ ^   ^ ^
Function: make-word-reader generator return
Function: make-grapheme-cluster-reader generator return

{gauche.unicode} generatorは文字またはコードポイントを生成するジェネレータで、 returnは文字またはコードポイントのリストを受け取り、オブジェクトを返す手続きです。 これらの手続きは、オブジェクト (単語またはgraphemeクラスタ) をひとつづつ生成する ジェネレータを返します。

ジェネレータgが文字列That's it.に含まれる文字を順に返す ジェネレータとすれば、作られるジェネレータの動作は次の通りです。

(define brk (make-word-reader g list->string))
(brk)  ⇒  "That's"
(brk)  ⇒  " "
(brk)  ⇒  "it"
(brk)  ⇒  "."
(brk)  ⇒  #<eof>

9.37.3 フルセットの大文字小文字変換

Function: string-upcase string
Function: string-downcase string
Function: string-titlecase string
Function: string-foldcase string

[R6RS][R7RS char][SRFI-129] {gauche.unicode} 与えられた文字列stringの大文字小文字を、Unicodeで定義された 言語独立のcase folding規則に基づいて変換します。 SRFI-13にも同名の手続きがありますが、そちらは文字ごとに変換する点で これらの手続きと異なります(文字列のケース(大文字小文字)マッピング参照)。 特に、こちらの手続きは元の文字列と変換後の文字列の長さが異なる場合があり、 また文字が単語境界にあるかどうかで変換が変わることもあります。 単語境界はUAX #29の規則に基づいて判断されます。

(string-upcase "straße")
 ⇒ "STRASSE"
(string-downcase "ΧΑΟΣΧΑΟΣ.ΧΑΟΣ. Σ.")
 ⇒ "χαοσχαοσ.χαος. σ."
(string-titlecase "You're talking about R6RS, right?")
 ⇒ "You're Talking About R6rs, Right?"
(string-foldcase "straße")
 ⇒ "strasse"
(string-foldcase "ΧΑΟΣΣ")
 ⇒ "χαοσσ"

string-upcasestring-downcasestring-foldcaseは R7RSのscheme.charモジュールでも提供されます。

string-titlecaseはSRFI-129でも定義されています。

Function: codepoints-upcase sequence
Function: codepoints-downcase sequence
Function: codepoints-titlecase sequence
Function: codepoints-foldcase sequence

{gauche.unicode} string-upcaseなどと同じですが、文字列ではなくコードポイント例を対象にします。 戻り値は入力と同じ型になります。

(codepoints-upcase '#(115 116 114 97 223 101))
 ⇒ #(83 84 82 65 83 83 69)
Function: string-ci=? string1 string2 string3 …
Function: string-ci<? string1 string2 string3 …
Function: string-ci<=? string1 string2 string3 …
Function: string-ci>? string1 string2 string3 …
Function: string-ci>=? string1 string2 string3 …

[R7RS char] {gauche.unicode} 文字列全体の大文字小文字変換を使って、大文字小文字の違いを無視した文字列比較を行います。

Gaucheは組み込みでstring-ci=?などを持っていますが、そちらは 文字ごとの大文字小文字変換を使います(文字列の色々な比較参照)。 それとは異なる手続きです。

(string-ci=? "\u00df" "SS") ⇒ #t

9.37.4 東アジア文字幅プロパティ

Function: char-east-asian-width char-or-codepoint

{gauche.unicode} 引数は文字か、Unicodeコードポイントを表す非負整数でなければなりません。 次のいずれかのシンボルを返します: N (neutral)、 F (fullwidth)、 H (halfwidth)、 W (wide)、 Na (narrow)、A (ambiguous)。

各シンボルの意味についてはUnicode standard annex #11を参照してください: http://unicode.org/reports/tr11/

Function: string-east-asian-width str :key F H W Na N A

{gauche.unicode} 東アジア文字幅プロパティを考慮して、文字列strの「幅」を計算して返します。 この幅は、概ね文字列を等幅フォントでターミナルに表示した場合の近似と考えることが できます。

もちろん実際に文字列が表示された時にどのくらいの幅を取るかは、実際にグリフを使って レンダリングしてみないとわかりません。が、文字列の構成要素がある程度限られている 場合は、ヒューリスティクスでだいたいうまくいきます。 例えば文字列がASCII文字とCJK漢字からなる場合、’Full-width’と’Wide’ プロパティの文字をASCII文字の2倍幅とみなすことができるでしょう。

この手続きは、各文字の「東アジア文字幅プロパティ」カテゴリに次の幅を割り当てます。 キーワード引数F, H, W, Na, N, A によってそれぞれの幅に違う値を割り当てることも可能です。

F (Full width)

2

H (Half width)

1

W (Wide)

2

Na (Narrow)

1

N (Neutral)

1

A (Ambiguous)

2

文字幅の考慮について詳しくは、UAX #11 (http://unicode.org/reports/tr11/) の5節を見てください。

(string-east-asian-width "abc") ⇒ 3
(string-east-asian-width "いろは") ⇒ 6
(string-east-asian-width "1番目" :W 1.5) ⇒ 4.0
Function: string-take-width str width :key F H W Na N A
Function: string-drop-width str width :key F H W Na N A

{gauche.unicode} string-takestring-drop (srfi.13 - 文字列ライブラリ参照) のように、 文字列strを指定箇所で切った前部分と後部分を返しますが、 文字数で切るかわりに文字の幅で切ります。

string-take-widthは、strのプレフィクスのうち、 そのstring-east-asian-widthwidthを越えない部分を返します。 一方string-drop-widthはそのプレフィクスを取り除いた部分を返します。

キーワード引数は東アジア文字幅のカテゴリから幅へのマッピングをカスタマイズするものです。 詳しくは上のstring-east-asian-widthの説明を見てください。



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT