aiscript-dev / aiscript

🔋 A lightweight scripting language runing on JavaScript
https://aiscript-dev.github.io/aiscript/
MIT License
190 stars 34 forks source link

codepoint_atで下位サロゲートが残っている #561

Open FineArchs opened 9 months ago

FineArchs commented 9 months ago

expected behaviour

let char = "𩸽" 
<: s.codepoint_at(0) // 171581
<: s.codepoint_at(1) // null

actual behaviour

let char = "𩸽" 
<: s.codepoint_at(0) // 171581
<: s.codepoint_at(1) // 56893
FineArchs commented 9 months ago

@MineCake147E 👀

MineCake147E commented 9 months ago

codepoint_atのインデックスは16bit単位なので、下位サロゲートの位置を直接指定した場合は下位サロゲートを返します。

FineArchs commented 9 months ago

あー、JavaScriptのcodePointAtがその仕様なんですね ただAiScriptにはcharcode_atもあることを考えると、codepoint_atはサロゲートペア単位にした方が用途が多いと思います

MineCake147E commented 9 months ago

to_unicode_arrto_unicode_codepoint_arrがコードポイントごとに区切るので、その用途ではそれをご利用ください。

<: `{'𩸽👉🏿👨‍👦'.to_unicode_arr()}`
<: `{'𩸽👉🏿👨‍👦'.to_unicode_codepoint_arr()}`
str [ "𩸽", "👉", "🏿", "👨", "‍", "👦" ]
str [ 171581, 128073, 127999, 128104, 8205, 128102 ]
(null)

こちらの方が、毎回分割するよりはパフォーマンス的にも良いかと思います。

FineArchs commented 9 months ago

仕様の形としては直感的でないですが、パフォーマンス的には確かにそうですね…

marihachi commented 9 months ago

codepoint_atでindexをコードポイント単位にはできないですかね?(ある程度パフォーマンスを維持しながら) もしできなさそうであれば、代替の方法もあるわけなのでこのAPIはあまり必要ない気がします。

MineCake147E commented 9 months ago

codepoint_atでindexをコードポイント単位にはできないですかね?(ある程度パフォーマンスを維持しながら)

出来なくはないかもしれませんが、互換性等を考慮すると、オプション引数を新設する必要があると思います。 毎回to_unicode_arr相当の処理を行うのは無駄が多いため現在の仕様となっています。(indexが0の場合だけ特殊対応をしてもいいかもしれませんが…)

もしできなさそうであれば、代替の方法もあるわけなのでこのAPIはあまり必要ない気がします。

to_unicode_arrしたものから一文字分のコードポイントを取得する際に必要になります。 毎回to_unicode_codepoint_arrを実行すると、毎回配列を返すことになり無駄が多いため、codepoint_atは結局必要だと思います。

marihachi commented 9 months ago

一文字からコードポイントの取得はこの関数しかないんですね... あとは、1文字にto_unicode_codepoint_arrして0番目を取りだすという方法もある?

marihachi commented 9 months ago

1文字からコードポイントを取得する関数があってもよさそうです。 それならcodepoint_atがなくても良いですよね?

MineCake147E commented 9 months ago

codepoint_at(0)を専用の関数にするということでよろしいですか?

marihachi commented 9 months ago
  1. 文字列をコードポイントの情報を元に文字やコードポイントに分割する
  2. 分割された文字を必要に応じてコードポイントに変換する

この流れでAPIを利用できれば十分だと思います

FineArchs commented 9 months ago

それだと機能が減るだけで変更のメリットが何もないような気がしますが…

marihachi commented 9 months ago

codepoint_atの下位サロゲートが残る問題はjsの仕様で仕方ないですけど、codepoint_atが無くなればその問題は解消されますね

marihachi commented 9 months ago

直感的でない部分が排除されることで、API全体の分かりやすさは向上すると思います。

marihachi commented 9 months ago

少し話が変わりますが jsが内部的にUTF-16で文字列を保持してるためインデックスもUTF-16コード単位になってると思うので、 AiScriptではコードポイントの配列を文字列の内部表現にするのもアリな気がしました。 コードポイント単位で文字が保持されているならcodepoint_atもうまく実装できそうです。 他のAPIはいろいろ検討する必要がありそうなので分かりませんが。

FineArchs commented 9 months ago

直感的でない部分が排除されることで、API全体の分かりやすさは向上すると思います。

うーんまあ確かにそうかもです

AiScriptではコードポイントの配列を文字列の内部表現にするのもアリな気がしました。

今の実装だと文字列処理では内部的にはJavaScriptの文字列をそのまま使っている訳ですが、それらを全部独自実装に置き換える感じですか?

marihachi commented 9 months ago

今の実装だと文字列処理では内部的にはJavaScriptの文字列をそのまま使っている訳ですが、それらを全部独自実装に置き換える感じですか?

独自実装といえばそうですね。 文字列からコードポイントの配列、コードポイントの配列から文字列への変換は、今でもやってるようにjsの機能で可能だと思うので、AiScriptのインタプリタが文字列を保持するときにはコードポイントの配列に変換しておくというイメージです。

FineArchs commented 9 months ago

毎回変換すると重くなりそうなので両方保持しておきたい気もします キャッシュみたいに必要次第で持っておくのもいいかも