プロジェクト

全般

プロフィール

機能 #447

完了

個人用 SKK 辞書の整理

nop_thread さんが5ヶ月前に追加. 2ヶ月前に更新.

ステータス:
終了
優先度:
通常
担当者:
開始日:
2024/08/03
期日:
進捗率:

100%

一時中断:
いいえ
pinned:
いいえ
確認予定日:
前回確認日:
2024/10/15
管理外残件あり:
いいえ

説明

2世代分の自作ユーティリティ用独自フォーマットでオリジナルデータが存在し、いいかげん統一的かつほどほどに端的なフォーマットにしたい。
あと、 skktools とか使ってインライン辞書登録したものを後から辞書ソースに移動するなどができるようにしたい。

nop_thread さんが5ヶ月前に更新

第1世代の skkcomp は読みと変換が多対多の場合の辞書生成を楽にするために作った。
これを展開して普通の skk 辞書形式にすると行が増えるし重複が発生しメンテも面倒になるので、この機構自体は (文法はさておき) 是非残したい。

第2世代の Rust 製で toml から辞書生成するやつは、読みやすく機械的生成もしやすいので便利はあるが、文法が冗長で書くのはダルい。
もう少し端的に書きたい。エントリを追加したいときに「他のエントリをコピーしてきて改変する」みたいなことをやりたくなるのはあまり健全でない。

nop_thread さんが5ヶ月前に更新 · 編集済み

まずはコンパクトでわかりやすい文法を考えないと始まらない。
分類とかネストとかはディレクトリ構造で表現すればいい気がするので、行指向であること、コメントを書けること、記号類の扱いが煩雑でないこと、あたりが条件か。

nop_thread さんが5ヶ月前に更新

nop_thread さんは #note-2 で書きました:

分類とかネストとかはディレクトリ構造で表現すればいい気がするので、

ファイル内の位置関係等で分類をしようとすると、ファイルを開いて初手の動作が「スクロールや検索で適切な位置に移動する」になるので面倒すぎる。
もっと「軽率に行末に足したうえでスクリプトを走らせると勝手にソートされる」くらいが良い。
(skktools の存在を考えるとソート自体不要なのだが、データを正規化しておきたかったり重複に気付きやすくしたいくらいの気持ちはあるので、ソートはしておく運用方針にした方が良い。)

nop_thread さんが5ヶ月前に更新

nop_thread さんは #note-2 で書きました:

行指向であること、コメントを書けること、

nop_thread さんは #note-3 で書きました:

もっと「軽率に行末に足したうえでスクリプトを走らせると勝手にソートされる」くらいが良い。

これらを併せて考えると、コメントはエントリの末尾とかに書ける必要がある。
さもなくば、ファイルを安直にソートするとコメントが対応するエントリから離れてしまう。

コメント記号の扱いを考えても、何らかの quotation の機構は必要か。

nop_thread さんが5ヶ月前に更新 · 編集済み

nop_thread さんは #note-1 で書きました:

第1世代の skkcomp は読みと変換が多対多の場合の辞書生成を楽にするために作った。
これを展開して普通の skk 辞書形式にすると行が増えるし重複が発生しメンテも面倒になるので、この機構自体は (文法はさておき) 是非残したい。

ちなみにこのときのフォーマットはこうだった:

よみいち/よみに/よみさん|候補1/候補2/候補3

たとえばこう使う。

ponponpain/haraitai/はらいたい/ぽんぺ/ぽんぽんぺいん|pͪoͣnͬpͣoͥnͭpͣa͡inͥ
きょうとあにめーしょん/きょうあに|京都アニメーション/京アニ

この形式は読みと候補が1対1のときも煩雑さを抑制できていたのが良かったが、間に空白を入れられないのは可読性を損なっていた。

また、上の例だと「きょうとあにめーしょん」は「京アニ」に変換されてほしくないと考えられるため、そのような完全な組み合わせの網羅をしたくない場合のケアもなかった。
新フォーマットではその辺りも何か考えたいところだ。

nop_thread さんが5ヶ月前に更新 · 編集済み

nop_thread さんは #note-5 で書きました:

また、上の例だと「きょうとあにめーしょん」は「京アニ」に変換されてほしくないと考えられるため、そのような完全な組み合わせの網羅をしたくない場合のケアもなかった。
新フォーマットではその辺りも何か考えたいところだ。

フォーマットをさておき概念としては、たとえば

[[entry]]
yomi = [
    { key = "きょうあに", verbosity = -2 },
    { key = "きょうとあにめーしょん", verbosity = -1 },
]
candidate = [
    { value = "京アニ", verbosity = -2 },
    { value = "京都アニメーション", verbosity = -1 },
]

のようにしておくと、「読み以上の verbosity を持つ候補だけを対応させる」というルールで きょうとあにめーしょん /京アニ/ という組み合わせを除外できる。

ちなみに verbosity を負にしたのは、対義語を思い付かなかった (abbr-level?) のと、読みも候補も略と展開の両方向への成長が考えられるからである。
たとえばこれを「きょ」で打ちたくなる日が来るかもしれないので verbosity を減らす方向へ成長する余地を残す必要があるし、また「株式会社京都アニメーション」へ変換したくなる日が来るかもしれないので verbosity を増すこともできる必要がある。
そうすると、 verbosity にせよ反対の軸にせよ、最初に想定していたレベル0よりも低い値を使う可能性は考えるべきである。
(べつにそれを想定して 100 とかから始めることを要請しても良いが、普通に気持ち悪いし、大概の用法では「最も冗長な文字列」は想定可能でそれを0に設定したくなるはず。)

nop_thread さんが5ヶ月前に更新

nop_thread さんは #note-6 で書きました:

「読み以上の verbosity を持つ候補だけを対応させる」というルールで

もうひとつの手としては、レベルが数値である必要はなく順序だけあれば良いので、読みと候補を分離せず混合するという方式が考えられる。

たとえば yomi=きょうあに, candidate=京アニ, yomi=きょうとあにめーしょん, candidate=京都アニメーション のようにして、「読みはそれより後ろで出現した候補へのみ変換できる」というルールにすればよい。
これなら完全な組み合わせの網羅も yomi=よみいち, yomi=よみに, yomi=よみさん, candidate=候補1, candidate=候補2, candidate=候補3のように自然に表現できる。

nop_thread さんが5ヶ月前に更新

nop_thread さんは #note-7 で書きました:

レベルが数値である必要はなく順序だけあれば良いので、

これについては真剣に考えると若干疑問なところもあり、略語というのは「どこを抽出するか」の候補が複数ありうるので、本当は1列にソートできず有向非巡回グラフなのではないか (つまり全対称律を満たさない半順序なのではないか) という気もしている。
ただこれを行指向で真面目に扱うのは些か面倒なので、そこはさすがに辞書エントリの複製なり変数/マクロ定義等の他の仕組みなりで誤魔化したいところである。

nop_thread さんが5ヶ月前に更新

nop_thread さんは #note-8 で書きました:

略語というのは「どこを抽出するか」の候補が複数ありうるので

典型的かつシンプルな候補としては、人名のようなものが挙げられるかもしれない。

はくれい /博麗/博麗霊夢/
れいむ /霊夢/博麗霊夢/
はくれいれいむ /博麗霊夢/

このようなエントリ群の生成は #note-6#note-7 の仕組みでは一発で生成できない。
「はくれい」と「れいむ」の verbosity が「はくれいれいむ」より低い点は共通しているが、かといって「はくれい」と「れいむ」のどちらがより verbose であるかは適切に定められないからである。
(verbosity を同等であるとしてしまうと はくれい /霊夢/れいむ /博麗/ が生成されてしまうが、これらは除外したいエントリである。)

nop_thread さんが5ヶ月前に更新 · 編集済み

もし単一の概念の変換エントリを複数行で表現するなら、先頭にキーのようなものを付けられるようにしないとソートでバラバラになってしまう。

verbosity が最大の候補を先頭にする (#note-7 の例示の逆順の記法にする) という手もあるが、どうだろう。
先頭に「The」とか「株式会社」とかが集まるような状況になると、それはそれで不便か?
かといってわざわざ ID 相当のものを全エントリに手打ちするのも面倒だ。
匿名で良いものの ID は全部 _ にするなどで誤魔化しても良いのだが、そうすると今度は ID のあるものとないものがそれぞれ集まり、似たような候補でも遠く離れた場所にソートされうることになってしまう。

nop_thread さんが5ヶ月前に更新

  • ステータス新規 から 進行中 に変更
  • 開始日2024/08/03 にセット
  • 前回確認日2024/08/03 にセット

nop_thread さんが5ヶ月前に更新

annotation は組み合わせ全体ではなく候補ごとに指定するのが望ましい。多少冗長になっても許容する。
たとえば候補「博麗」と「霊夢」に対しては「博麗霊夢」であるというアノテーションを与えたいかもしれないが、同じものを候補「博麗霊夢」そのものには与えたくないといったように、略語と正式表記では一般に異なるアノテーションを与えたいと考えられる。

nop_thread さんが5ヶ月前に更新

エスケープについて。

カンマなり空白なりスラッシュなりを読みと候補で使うことは十分に考えられるが、かといってこれらの文字を文法レベルの区切り文字として使えないというのも不便なので、エスケープか quotation は必須ということにして直観的な文法にしてしまいたい。
たとえば double quotation で括るくらいなら手間としては許容範囲だろう。
Unicode codepoint を \u{1F914} などのように入力する文法を導入できるなど拡張性も担保できる。

Unicode の EAW 等の特殊な一部の符号はターミナル上で文字幅が狂ったり結合してカーソル移動が面倒になったりで大変なので、これらをエスケープできると少し嬉しい。
スクリプトによる自動生成も幾分やりやすくなるかもしれない。

nop_thread さんが5ヶ月前に更新 · 編集済み

nop_thread さんは #note-10 で書きました:

verbosity が最大の候補を先頭にする (#note-7 の例示の逆順の記法にする) という手もあるが、どうだろう。
先頭に「The」とか「株式会社」とかが集まるような状況になると、それはそれで不便か?

“正式な” 表記でソートされて困る例としては、数字のデコレーションやスタイリングが挙げられる。

  • U+24EA CIRCLED DIGIT ZERO () は U+2460 CIRCLED DIGIT ONE () 〜 U+2473 CIRCLED NUMBER TWENTY () よりも後ろ、しかし U+3251 CIRCLED NUMBER TWENTY ONE () よりも前にある。
  • U+1F100 DIGIT ZERO FULL STOP (🄀) は U+249B NUMBER TWENTY FULL STOP () よりも後ろにある。
  • 上付き数字のコードポイントは以下の順である。
    • U+00B2 SUPERSCRIPT TWO (²)
    • U+00B3 SUPERSCRIPT THREE (³)
    • U+00B9 SUPERSCRIPT ONE (¹)
    • U+2070 SUPERSCRIPT ZERO ()
    • U+2074 SUPERSCRIPT FOUR ()
    • (以後5〜9が U+2074〜U+2079)

こういった例外を含むカテゴリを適切に小さな別ファイルに分離すれば良いという考えもある。
行数がそこまで膨らまなければ、多少ソートが崩れようと大した問題ではないか。

nop_thread さんが5ヶ月前に更新

今のところ、以下のような文法を考えている。

c"候補1" c"候補2" y"よみいち" y"よみ2" c"候補3" y"よみ3"

順序は #note-10 で考えた理由から、 #note-7 の逆順。
つまり「それぞれの候補は、その後ろで出現した各種の読みからのみ変換できる」という解釈。
c="候補" とか cand="候補" のようなものは冗長なので c"候補" としているが、 raw string literal のような別種・追加の文字列形式 (r##"this is "hello world" and r#"this is raw string literal"#"## とか) を導入できる拡張性を考えるとイコール記号くらいはあっても良い気がする。
セパレータとしても記号が続いた方が視認性が上がるかもしれない。

nop_thread さんが5ヶ月前に更新

annotation の分離はどうしよう。
変換候補中にセミコロンを入れたいことは十分にありうるから、一応 string 内ではエスケープ不要にしておいて、 a"annotation" のように候補の後ろに与えるような形式でも良い気はする。
気はするが、「後ろを見ないと出力が確定しない」というのはスクリプトを書くときダルいかも。
どうせ書けば使い回すんだから最初の1回くらいちゃんと書けという話もあるが。

nop_thread さんが5ヶ月前に更新

末尾に disabled とか enable=false とかを与えると候補が生成されなくなる、みたいな仕掛けも面白そう。
こうすると、行コメント記号を先頭に挿入する方式とは違ってコメントアウトがソートへの影響を与えなくなるので管理しやすくなる。

nop_thread さんが5ヶ月前に更新

空白と quotation character と escape character が出現しない限りにおいては " は省略できるか?
こういう文法は好きではないが、行内に何度も =" を書くのは少々ダルい。

nop_thread さんが5ヶ月前に更新

nop_thread さんは #note-18 で書きました:

空白と quotation character と escape character が出現しない限りにおいては " は省略できるか?

できるとは思うが、ソートしたとき quotation の有無で分裂してしまうから避けた方が良さそうだ。

nop_thread さんが5ヶ月前に更新 · 編集済み

  • c: candidate。候補
  • a: annotation。アノテーション
  • y: yomi。読み
  • enable: この行からエントリを生成するかどうか。文字列ではなく truefalse を持つ。
  • note: メモ。変換候補の生成に影響しない
  • g: group。行の先頭に付けてソートに使う。 g="person" とか g="voiceline" とか。
    • わざわざファイルを分割するほどではないがグルーピングはしたい、みたいな場合に使える?
    • たとえばプリプロセスで `g="<作品>" g="地名" のようにすると、複数の作品のエントリ群を単一ファイルに置くなどもでき、応用範囲は広そう。 (ファイルを分けるべきと思うが、2行や3行のファイルが大量にあっても仕方がない。)

nop_thread さんが5ヶ月前に更新

  • 進捗率0 から 20 に変更

移植中。
変換スクリプトはまだ書いていないが、 sane syntax なので簡単に書けるだろう。
シェルスクリプトで書くか Rust でやるかは検討の余地があるが。

nop_thread さんが5ヶ月前に更新

  • 進捗率20 から 50 に変更

Unicode 系のもの以外はだいたい移植できた。

nop_thread さんが5ヶ月前に更新

  • 進捗率50 から 70 に変更
  • 管理外残件ありいいえ にセット

https://mastodon.cardina1.red/@lo48576/112909194602666658

変換スクリプトは結局 Rust で雑に書けた。
書けたはいいが、エスケープとか記号類まわりで libskk の不具合か何かを踏み抜いたっぽいので、このままでは「しょぼん」したとき fcitx が再起動する。つらい。

nop_thread さんが5ヶ月前に更新

  • 前回確認日2024/08/03 から 2024/08/05 に変更

nop_thread さんが5ヶ月前に更新

  • 進捗率70 から 80 に変更
  • 前回確認日2024/08/05 から 2024/08/06 に変更

Fix crash when non-ASCII character follows an escaped characters by lo48576 · Pull Request #88 · ueno/libskk

パッチを書いてローカルで当てたところ、問題なく動いている。
勝ちです。

nop_thread さんが5ヶ月前に更新

残すは Unicode の記号系だけ。

nop_thread さんが2ヶ月前に更新

  • ステータス進行中 から 終了 に変更
  • 進捗率80 から 100 に変更
  • 前回確認日2024/08/06 から 2024/10/15 に変更

統合完了。
compdic 自体の自動生成まわりはもう少しどうにかしたいが、とりあえず単一リポジトリからすべての辞書を生成できる一貫した状態になった。

他の形式にエクスポート: Atom PDF