【IRIS/Cache】「𩸽(ホッケ)」サロゲートペアの料理方法について

はじめに

「𩸽」美味しいですよね。
「𩸽」開きを焼いて、大根おろしと共に食べる。最高です!

でも、プログラムの世界では「𩸽」は、まったくオイシクナイデス。

今回は、IRIS/Cacheでの「𩸽」のおいしい料理方法をご紹介いたします。

サロゲートペアとは

そもそもサロゲートペアとは何?

日本語のUnicodeでは1文字につき、基本2バイト文字になります。
ただ、使用したい文字が増えたため、1文字4バイトとして新たに使用できるようにしました。

IRIS/Cacheではどうなるか?

サロゲートペアの事が分かったので、IRIS/Cacheではどう振舞うか確認したいと思います。

s str="𩸽"
w $l(str)

一文字しか無いのに、文字の長さが2文字と表示されました。
4バイト文字のため、誤検知していますね。

$length()で誤検知しているので、$extract()でも怪しい動作をします。
4バイト中の2バイトを切り取ってしまうので、正しい文字として表示できません。

s str="𩸽が食べたい"
w $e(str)_"を食べるぞ"

流石に文字の幅($zwidth)は、正常に算出されましたね。

w $zwidth(str)

文字の反転($reverse)

w $reverse("あい𩸽えお")

検索の$findも「お」の位置がずれますね。

w $f("あい𩸽えお","お")
w $f("あいうえお","お")

文字コードの取得($ascii, $char)

w $a("𩸽") // 文字 > 文字コード
w $c(55399) // 文字コード > 文字
w $a("あ")
w $c(12354)

文字を操作するObjectScriptは、どれも軒並み全滅しているのが確認できました。
あぁ、「𩸽」オイシクナイヨ…(笑

対応策

各種ObjectScriptは、コマンドの先頭に「w」を付ければ大体OKです!(笑

どのコマンドも、サロゲートペアが含まれていなくても正常に動作します。
ただ、ちょっぴり遅いとドキュメントに記載されています。

サロゲートペアが含まれているかチェックをする

サロゲートペアに対応したコマンドは、処理が遅いと言われています。
その為、まず最初に文字列にサロゲートペアが含まれているか判断する必要があります。

w $wiswide("あいうえお")
w $wiswide("あい𩸽えお")

1が返る事で、文字列にサロゲートペアが含まれている事を取得できます。

文字数を取得する

$length()では正常に取得出来なかった文字数も、$wlength()で取得する事が出来ます。

w $wl("あい𩸽えお")
w $wl("あいうえお")

文字の切り取り

$extract()ではなく、$wextract()になります。

s str="𩸽が食べたい"
w $we(str)_"を食べるぞ"

文字の反転

$reverse()は、$wreverse()になります。

w $wreverse("あい𩸽えお")
w $wreverse("あいうえお")

文字の検索

$find()は、$wfind()で対応できます。

w $wf("あい𩸽えお","お")
w $wf("あいうえお","お")

文字コードの操作

$ascii()が$wascii()になり、$char()が$wchar()で対応ができます。

w $wa("𩸽") // 文字 > 文字コード
w $wc(171581) // 文字コード > 文字
w $wa("あ") // 文字 > 文字コード
w $wc(12354) // 文字コード > 文字

通常版とどのくらい処理速度が変わるんだろう?

ドキュメントを読む限りでは、サロゲートペアに対応した「w」系のコマンドは、通常版より処理速度が遅いと記述されています。

実際、どの程度処理速度に差があるのか、確かめてみます。

$length()と$wlength()の速度差

$length()と$wlength()の速度をチェックしてみましょう。

ClassMethod checklengthSpeed(cnt As %Integer = 10000, str As %String)
{
	s start = $zh
	f pos = 1:1:cnt s str = $l(str)
	w !,"通常:"_($zh-start)	
	
	s start = $zh
	f pos = 1:1:cnt s str = $wl(str)
	w !,"対応:"_($zh-start)
}

文字数を20文字にして確かめてみます。

あれ?あまり時間差がないゾ・・・
同じ処理の反復は、差が出にくいのでしょうか。

文字数を100文字にして確認

s str=str_str_str_str_str
w $l(str)
d ##class(developer.Sample).checklengthSpeed(10000,str)

この検証方法では、両コマンドの差は誤差レベルと思えます・・・

$extract()と$wextract()で速度差を比較する

$extract()は使い方が幅広いので、文字列中の1文字を切り取る形での速度差を検証してみたいと思います。

ClassMethod checkextractSpeed(cnt As %Integer = 10000, str As %String, pos as %Integer = 10)
{
	s start = $zh
	f pos = 1:1:cnt s str = $e(str,pos)
	w !,"通常:"_($zh-start)	
	
	s start = $zh
	f pos = 1:1:cnt s str = $we(str,pos)
	w !,"対応:"_($zh-start)
}

$length検証と同じく20文字から始めてみたいと思います。
20文字中の10文字を切り取る形でスタート!

s str = "あいうえおかきくけこさしすせそたちつてと"
d ##class(developer.Sample).checkextractSpeed(10000,str)

あれ、サロゲートペア対応の方が若っっっ干早いですね。
ほぼ誤差レベルの差なので、気にする必要は無さそうです。

とりあえず、100文字中の40番目を切り取る形で検証してみます。

s str = str_str_str_str_str
w $l(str)
d ##class(developer.Sample).checkextractSpeed(10000,str,40)

・・・

オカシイな。
まぁ、うん。ほぼ誤差なので気にしない事にします。

終わりに

ドキュメントを読む限りでは、サロゲート対応版より通常版のコマンドの方が高速のため、そちらを使用する事を推奨していますが、検証した限りではあまり速度差が無いですね。
もっと文字数の多い文字列であれば、差がでてくるのでしょうか。

一先ず、$wiswide()を利用して、サロゲートペアが文字列中に含まれているかを判断し、コマンドの使い分けをした方が無難と考えます。

以上、サロゲートペアの美味しい料理の仕方でした!