はじめに
こんにちは。sabapenです。
先日、Twitter(新X)で全俳句データベースというWebアプリが話題になっていました。
あ~んの50音+濁音等のひらがなの全ての組み合わせにIDを振って網羅した一種のジョークアプリとなっております。
ありそうでなかった発想の勝利とも思える作品に感動した私は、自分も似たようなWebアプリを作ってみようと思い立ち、Viteの練習も兼ねつつ全四字熟語データベースを作成しました。
全四字熟語データベースでは2136文字の常用漢字を使った約20兆通りの四字熟語を網羅する必要があります。その際に気をつけた以下の3つの注意点に関してこの記事で解説したいと思います。
- 常用漢字の判定
- 漢字の組み合わせとIDの1対1対応
- 20兆程度の大規模な組み合わせ
制作物
全四字熟語データベースはVite+React+Typescriptを使って3時間ほどでサクッと制作しました。そのためUIが適当だったりコードが十分に最適化されていなかったりする点には目をつぶっていただけると幸いです。
常用漢字の判定
最初に躓いたのは常用漢字の判定です。常用漢字を判定できるライブラリがあればいいなぁと思って探してみましたが見つからなかったので、ここは力技で解決しました。
UTF-8で常用漢字のCSVを配布してくださっているありがたいサイト1があったため、CSVを落としてきてJSONとして整えて利用しています。
{
"1": "亜",
"2": "哀",
"3": "挨",
"4": "愛",
"5": "曖",
"6": "悪",
...(省略)
}
あとはJSONをこねこねして入力された文字が含まれるか否かを判定すればOKですね。
文字コードの範囲で正規表現にかけたりすればもっとスマートなやり方はありそうですが、高々2136通りなので力技でやるのが一番速いと思います。
漢字の組み合わせとIDの1対1対応
次は漢字四文字の組み合わせとIDの1対1対応の取り方です。
こちらは四字熟語を2136進数の4ケタの数字とみなし、10進数へ変換することでIDと対応させることができます。
function getYojijukugoId(yojijukugo: string): number {
const str = [...yojijukugo]
const kanjiIds = str.map(
(kanji) =>
joyokanjiArray.find((joyokanji) => joyokanji.kanji === kanji)!.kanjiId,
)
const yojijukugoId =
(kanjiIds[0] - 1) * joyokanjiArray.length ** 3 +
(kanjiIds[1] - 1) * joyokanjiArray.length ** 2 +
(kanjiIds[2] - 1) * joyokanjiArray.length +
(kanjiIds[3] - 1) +
1
return yojijukugoId
}
上記の関数では、四字熟語の1文字目は2136進数の4桁目なので2136の3乗をかけ、2文字目は2136の2乗をかけ、……と繰り返すことでIDと1対1で変換しています。
50音なら50進数として扱いますし、アルファベット26文字なら26進数として取り扱うことができます。このような変換は意外と役に立ちますね。
20兆程度の大規模な組み合わせ
四字熟語の組み合わせは2136^4=20,816,369,750,016ということで、約20兆通り存在します。ここで気をつける必要があるのが、オーバーフローです。
Javascriptの仕様
Javascriptでは数値を倍精度浮動小数で取り扱う関係上、整数として正確に扱える安全な値は-(2^53 − 1)から2^53 − 1の間、おおよそ+-900京までとなっています。
これよりも大きい値になる場合はなんらかの対応が必要となってきます。
本家全俳句データベース
本家全俳句データベースでは約6溝(こう)句を取り扱っている関係上、900京を遥かに上回る値になってしまいます。そのため、BigInt型を使って製作していたようです2
全四字熟語データベース
では、全四字熟語データベースではどうしたかというと約20兆通りで900京まで全然余裕があったので普通のnumber型で制作できました。
オーバーフローには注意が必要ですが、問題がなければ無理にBigIntを使う必要はないですね。
おわりに
全四字熟語データベースを作ってみると、簡単そうに見えていくつか注意点がありました。IDと紐づける必要のあるような制作物を作る際は参考にしてもらえると幸いです。