Compare commits
2 commits
4fb005ce09
...
2cbe8462ae
Author | SHA1 | Date | |
---|---|---|---|
2cbe8462ae | |||
9ec50677d9 |
6 changed files with 406 additions and 33 deletions
|
@ -8317,7 +8317,6 @@
|
||||||
おうようじょう 応用上
|
おうようじょう 応用上
|
||||||
おうようじょうほう 応用情報
|
おうようじょうほう 応用情報
|
||||||
おうようじょうほうがく 応用情報学
|
おうようじょうほうがく 応用情報学
|
||||||
おうじょうけん 応用情報学研究センター
|
|
||||||
おうようすいしんか 応用推進課
|
おうようすいしんか 応用推進課
|
||||||
おうようすうがく 応用数学
|
おうようすうがく 応用数学
|
||||||
おうようすうがっか 応用数学科
|
おうようすうがっか 応用数学科
|
||||||
|
@ -14908,7 +14907,6 @@
|
||||||
かんいしんぱん 簡易新版
|
かんいしんぱん 簡易新版
|
||||||
かんいてき 簡易的
|
かんいてき 簡易的
|
||||||
かんいほけん 簡易保険
|
かんいほけん 簡易保険
|
||||||
かんいほけんほーる 簡易保険ホール
|
|
||||||
かんいほうしき 簡易方式
|
かんいほうしき 簡易方式
|
||||||
かんいむせん 簡易無線
|
かんいむせん 簡易無線
|
||||||
かんけつ 簡潔
|
かんけつ 簡潔
|
||||||
|
@ -42588,7 +42586,6 @@
|
||||||
しょせきるい 書籍類
|
しょせきるい 書籍類
|
||||||
しょせん 書泉
|
しょせん 書泉
|
||||||
しょせんぐらんで 書泉グランデ
|
しょせんぐらんで 書泉グランデ
|
||||||
しょせんぶっくまーと 書泉ブックマート
|
|
||||||
しょたい 書体
|
しょたい 書体
|
||||||
しょだな 書棚
|
しょだな 書棚
|
||||||
かきおき 書置
|
かきおき 書置
|
||||||
|
@ -46961,7 +46958,6 @@
|
||||||
しんにっぽん 新日本
|
しんにっぽん 新日本
|
||||||
しんにほんしょうけん 新日本証券
|
しんにほんしょうけん 新日本証券
|
||||||
しんにほんせいてつ 新日本製鉄
|
しんにほんせいてつ 新日本製鉄
|
||||||
しんにってつ 新日本製鉄株式会社
|
|
||||||
しんにほんせいてつ 新日本製鐵
|
しんにほんせいてつ 新日本製鐵
|
||||||
しんにっぽんせいてつ 新日本製鐵
|
しんにっぽんせいてつ 新日本製鐵
|
||||||
しんにってつ 新日鐵
|
しんにってつ 新日鐵
|
||||||
|
@ -54141,7 +54137,6 @@
|
||||||
せんこうちゅう 選考中
|
せんこうちゅう 選考中
|
||||||
せんこうび 選考日
|
せんこうび 選考日
|
||||||
せんこう 選鉱
|
せんこう 選鉱
|
||||||
せんけん 選鉱精錬研究所
|
|
||||||
せんじゃ 選者
|
せんじゃ 選者
|
||||||
せんしゅ 選手
|
せんしゅ 選手
|
||||||
せんしゅいちらん 選手一覧
|
せんしゅいちらん 選手一覧
|
||||||
|
@ -62107,7 +62102,6 @@
|
||||||
ちゅうがくせいばん 中学生版
|
ちゅうがくせいばん 中学生版
|
||||||
ちゅうがくにゅうしもんだい 中学入試問題
|
ちゅうがくにゅうしもんだい 中学入試問題
|
||||||
ちゅうかっこ 中括弧
|
ちゅうかっこ 中括弧
|
||||||
なかま 中間
|
|
||||||
ちゅうかんれべるがくしゅう 中間レベル学習
|
ちゅうかんれべるがくしゅう 中間レベル学習
|
||||||
ちゅうかんえき 中間駅
|
ちゅうかんえき 中間駅
|
||||||
ちゅうかんえきしはつ 中間駅始発
|
ちゅうかんえきしはつ 中間駅始発
|
||||||
|
@ -66471,7 +66465,6 @@
|
||||||
でんしききぶ 電子機器部
|
でんしききぶ 電子機器部
|
||||||
でんしぎじゅつ 電子技術
|
でんしぎじゅつ 電子技術
|
||||||
でんしぎじゅつしゃ 電子技術者
|
でんしぎじゅつしゃ 電子技術者
|
||||||
でんそうけん 電子技術総合研究所
|
|
||||||
でんしきょう 電子協
|
でんしきょう 電子協
|
||||||
でんしけいじばん 電子掲示板
|
でんしけいじばん 電子掲示板
|
||||||
でんしけい 電子系
|
でんしけい 電子系
|
||||||
|
@ -66486,7 +66479,6 @@
|
||||||
でんしこうがくきょうしつ 電子工学教室
|
でんしこうがくきょうしつ 電子工学教室
|
||||||
でんしこうがくせんこう 電子工学専攻
|
でんしこうがくせんこう 電子工学専攻
|
||||||
でんしこうぎょう 電子工業
|
でんしこうぎょう 電子工業
|
||||||
でんしきょう 電子工業振興協会
|
|
||||||
でんしこうさく 電子工作
|
でんしこうさく 電子工作
|
||||||
でんしざいりょう 電子材料
|
でんしざいりょう 電子材料
|
||||||
でんししき 電子式
|
でんししき 電子式
|
||||||
|
@ -67641,7 +67633,6 @@
|
||||||
とうきょうがす 東京ガス
|
とうきょうがす 東京ガス
|
||||||
とうきょうすたいる 東京スタイル
|
とうきょうすたいる 東京スタイル
|
||||||
とうきょうてあとる 東京テアトル
|
とうきょうてあとる 東京テアトル
|
||||||
とうきょうべいえぬけーほーる 東京ベイNKホール
|
|
||||||
とうきょういがい 東京以外
|
とうきょういがい 東京以外
|
||||||
とうきょういち 東京一
|
とうきょういち 東京一
|
||||||
とうきょうえき 東京駅
|
とうきょうえき 東京駅
|
||||||
|
@ -68467,7 +68458,6 @@
|
||||||
とうけいしょり 統計処理
|
とうけいしょり 統計処理
|
||||||
とうけいじょうほう 統計情報
|
とうけいじょうほう 統計情報
|
||||||
とうけいすうがく 統計数学
|
とうけいすうがく 統計数学
|
||||||
とうすうけん 統計数理研究所
|
|
||||||
とうけいち 統計値
|
とうけいち 統計値
|
||||||
とうけいてき 統計的
|
とうけいてき 統計的
|
||||||
とうけいてきぱたあん 統計的パターン
|
とうけいてきぱたあん 統計的パターン
|
||||||
|
@ -71469,12 +71459,10 @@
|
||||||
にっぽんとむそん 日本トムソン
|
にっぽんとむそん 日本トムソン
|
||||||
にっぽんはむ 日本ハム
|
にっぽんはむ 日本ハム
|
||||||
にほんはむ 日本ハム
|
にほんはむ 日本ハム
|
||||||
にっぽんひゅーむかん 日本ヒューム管
|
|
||||||
にっぽんびくたー 日本ビクター
|
にっぽんびくたー 日本ビクター
|
||||||
にっぽんぺいんと 日本ペイント
|
にっぽんぺいんと 日本ペイント
|
||||||
にっぽんゆにばっく 日本ユニバック
|
にっぽんゆにばっく 日本ユニバック
|
||||||
にっぽんれーす 日本レース
|
にっぽんれーす 日本レース
|
||||||
にほんろぼっとがっかい 日本ロボット学会
|
|
||||||
にほんいがい 日本以外
|
にほんいがい 日本以外
|
||||||
にほんいじょう 日本以上
|
にほんいじょう 日本以上
|
||||||
にほんいち 日本一
|
にほんいち 日本一
|
||||||
|
@ -72032,8 +72020,6 @@
|
||||||
にゅうしゅつりょく 入出力
|
にゅうしゅつりょく 入出力
|
||||||
にゅうしゅつりょくh 入出力
|
にゅうしゅつりょくh 入出力
|
||||||
にゅうしゅつりょくせっと 入出力セット
|
にゅうしゅつりょくせっと 入出力セット
|
||||||
にゅうしゅつりょくぱ 入出力パターン
|
|
||||||
にゅうしゅつりょくぱたーん 入出力パターン
|
|
||||||
にゅうしゅつりょくかんけい 入出力関係
|
にゅうしゅつりょくかんけい 入出力関係
|
||||||
にゅうしゅつりょくけい 入出力系
|
にゅうしゅつりょくけい 入出力系
|
||||||
にゅうしゅつりょくそうち 入出力装置
|
にゅうしゅつりょくそうち 入出力装置
|
||||||
|
@ -79676,7 +79662,6 @@
|
||||||
ぶんいちそうごうしゅっぱん 文一総合出版
|
ぶんいちそうごうしゅっぱん 文一総合出版
|
||||||
ぶんえんどう 文苑堂
|
ぶんえんどう 文苑堂
|
||||||
ぶんか 文化
|
ぶんか 文化
|
||||||
ぶんかしゃったー 文化シャッター
|
|
||||||
ぶんかかい 文化会
|
ぶんかかい 文化会
|
||||||
ぶんかかいかん 文化会館
|
ぶんかかいかん 文化会館
|
||||||
ぶんかかいかん 文化会舘
|
ぶんかかいかん 文化会舘
|
||||||
|
@ -80078,7 +80063,6 @@
|
||||||
へいおん 平温
|
へいおん 平温
|
||||||
へいおん 平穏
|
へいおん 平穏
|
||||||
ひらかな 平仮名
|
ひらかな 平仮名
|
||||||
ひらかなかくていにゅうりょく 平仮名確定入力
|
|
||||||
へいか 平価
|
へいか 平価
|
||||||
へいけ 平家
|
へいけ 平家
|
||||||
へいけものがたり 平家物語
|
へいけものがたり 平家物語
|
||||||
|
@ -110778,7 +110762,6 @@
|
||||||
せんせいよう 先生用
|
せんせいよう 先生用
|
||||||
せんせんげつ 先先月
|
せんせんげつ 先先月
|
||||||
せんたんいりょう 先端医療
|
せんたんいりょう 先端医療
|
||||||
せんたんかがくぎじゅつけんきゅうせんたー 先端科学技術研究センター
|
|
||||||
せんたんぎじゅつけんきゅう 先端技術研究
|
せんたんぎじゅつけんきゅう 先端技術研究
|
||||||
せんたんきょうふしょう 先端恐怖症
|
せんたんきょうふしょう 先端恐怖症
|
||||||
せんたんけん 先端研
|
せんたんけん 先端研
|
||||||
|
@ -114513,7 +114496,6 @@
|
||||||
でんしききるい 電子機器類
|
でんしききるい 電子機器類
|
||||||
でんしきどう 電子軌道
|
でんしきどう 電子軌道
|
||||||
でんしぎじゅつかんけい 電子技術関係
|
でんしぎじゅつかんけい 電子技術関係
|
||||||
でんしぎじゅつそうごうけんきゅうしょ 電子技術総合研究所
|
|
||||||
でんしけいじばん 電子掲示版
|
でんしけいじばん 電子掲示版
|
||||||
でんしけいさんきしつ 電子計算機室
|
でんしけいさんきしつ 電子計算機室
|
||||||
でんしこうさくよう 電子工作用
|
でんしこうさくよう 電子工作用
|
||||||
|
@ -116022,7 +116004,6 @@
|
||||||
にほんちんぼつ 日本沈没
|
にほんちんぼつ 日本沈没
|
||||||
にほんていえん 日本庭園
|
にほんていえん 日本庭園
|
||||||
にほんてつどう 日本鉄道
|
にほんてつどう 日本鉄道
|
||||||
にほんにんちかがくかい 日本認知科学会
|
|
||||||
にほんねこ 日本猫
|
にほんねこ 日本猫
|
||||||
にほんばんじまく 日本版字幕
|
にほんばんじまく 日本版字幕
|
||||||
にほんぶっきょう 日本仏教
|
にほんぶっきょう 日本仏教
|
||||||
|
@ -116115,7 +116096,6 @@
|
||||||
にゅうよくざい 入浴剤
|
にゅうよくざい 入浴剤
|
||||||
にゅうよくはっぽうき 入浴発泡器
|
にゅうよくはっぽうき 入浴発泡器
|
||||||
にゅうらい 入来
|
にゅうらい 入来
|
||||||
にゅうりょくぱらめーた 入力パラメータ
|
|
||||||
にゅうりょくかんじ 入力漢字
|
にゅうりょくかんじ 入力漢字
|
||||||
にゅうりょくかんきょう 入力環境
|
にゅうりょくかんきょう 入力環境
|
||||||
にゅうりょくじたい 入力自体
|
にゅうりょくじたい 入力自体
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
mod phfbin_gen;
|
mod phfbin_gen;
|
||||||
|
mod testconv;
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::HashMap, path::Path};
|
use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||||
|
|
||||||
|
@ -66,12 +67,13 @@ fn parse_dict_ln(records: &mut Records, line: &str, ln: usize) {
|
||||||
.or_else(|| context.map(str::to_owned))
|
.or_else(|| context.map(str::to_owned))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
) {
|
) {
|
||||||
std::collections::hash_map::Entry::Occupied(mut e) => {
|
std::collections::hash_map::Entry::Occupied(_) => {
|
||||||
// Replace reading if the new one is longer
|
/*
|
||||||
|
// Replace reading if the new one is shorter
|
||||||
let val = e.get_mut();
|
let val = e.get_mut();
|
||||||
if val.len() < reading.len() {
|
if val.len() > reading.len() {
|
||||||
*val = reading.to_owned();
|
*val = reading.to_owned();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
std::collections::hash_map::Entry::Vacant(e) => {
|
std::collections::hash_map::Entry::Vacant(e) => {
|
||||||
e.insert(reading.to_owned());
|
e.insert(reading.to_owned());
|
||||||
|
@ -198,9 +200,63 @@ impl Encodable for Readings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_redundant_compounds(dict: &Records) -> Records {
|
||||||
|
let mut wdict = dict.clone();
|
||||||
|
|
||||||
|
for (kanji, readings) in dict {
|
||||||
|
if kanji.chars().count() <= 3 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if readings.len() != 1 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(reading) = readings.get("") {
|
||||||
|
// Try to convert the entry without it being present
|
||||||
|
let entry = wdict.remove_entry(kanji).unwrap();
|
||||||
|
let res = testconv::convert(kanji, &wdict);
|
||||||
|
|
||||||
|
if &res == reading || to_romaji_nodc(&res) == to_romaji_nodc(reading) {
|
||||||
|
println!("Redundant: {} - {}", kanji, reading);
|
||||||
|
} else {
|
||||||
|
// Put the entry back if it is necessary
|
||||||
|
wdict.insert(entry.0, entry.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wdict
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Romanize and remove double consonants
|
||||||
|
fn to_romaji_nodc(text: &str) -> String {
|
||||||
|
let rom = wana_kana::to_romaji::to_romaji(text);
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
let mut citer = rom.chars().peekable();
|
||||||
|
|
||||||
|
while let Some(c) = citer.next() {
|
||||||
|
if matches!(c, 'a' | 'e' | 'i' | 'o' | 'u') {
|
||||||
|
match citer.peek() {
|
||||||
|
Some(nc) => {
|
||||||
|
if &c != nc {
|
||||||
|
buf.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => buf.push(c),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_kanji_dict() -> Vec<u8> {
|
fn generate_kanji_dict() -> Vec<u8> {
|
||||||
let mut records = Records::default();
|
let mut records = Records::default();
|
||||||
parse_dict(&mut records, Path::new("dict/kakasidict.utf8"));
|
parse_dict(&mut records, Path::new("dict/kakasidict.utf8"));
|
||||||
|
records = find_redundant_compounds(&records);
|
||||||
|
|
||||||
|
println!("kanji_dict: {} entries", records.len());
|
||||||
|
|
||||||
let mut phfmap = phfbin_gen::Map::<KanjiString, Readings>::default();
|
let mut phfmap = phfbin_gen::Map::<KanjiString, Readings>::default();
|
||||||
for (kanji, readings) in records {
|
for (kanji, readings) in records {
|
||||||
|
|
196
codegen/src/testconv.rs
Normal file
196
codegen/src/testconv.rs
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
use crate::{Records, CLETTERS};
|
||||||
|
|
||||||
|
const ENDMARK: [char; 11] = [
|
||||||
|
')', ']', '!', '.', ',', '\u{3001}', '\u{3002}', '\u{ff1f}', '\u{ff10}', '\u{ff1e}', '\u{ff1c}',
|
||||||
|
];
|
||||||
|
const DASH_SYMBOLS: [char; 4] = ['\u{30FC}', '\u{2015}', '\u{2212}', '\u{FF70}'];
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum CharType {
|
||||||
|
Kanji,
|
||||||
|
Katakana,
|
||||||
|
Hiragana,
|
||||||
|
Symbol,
|
||||||
|
Alpha,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert(text: &str, dict: &Records) -> String {
|
||||||
|
// TODO: char conversion should be done with iterators
|
||||||
|
let mut char_indices = text.char_indices();
|
||||||
|
let mut kana_text = String::new();
|
||||||
|
let mut hiragana = String::new();
|
||||||
|
let mut prev_type = CharType::Kanji;
|
||||||
|
|
||||||
|
// output_flag
|
||||||
|
// means (output buffer?, output text[i]?, copy to buffer and increment i?)
|
||||||
|
// possible (False, True, True), (True, False, False), (True, True, True)
|
||||||
|
// (False, False, True)
|
||||||
|
|
||||||
|
while let Some((i, c)) = char_indices.next() {
|
||||||
|
let output_flag = if ENDMARK.contains(&c) {
|
||||||
|
(CharType::Symbol, true, true, true)
|
||||||
|
} else if DASH_SYMBOLS.contains(&c) {
|
||||||
|
(prev_type, false, false, true)
|
||||||
|
} else if is_sym(c) {
|
||||||
|
if prev_type != CharType::Symbol {
|
||||||
|
(CharType::Symbol, true, false, true)
|
||||||
|
} else {
|
||||||
|
(CharType::Symbol, false, true, true)
|
||||||
|
}
|
||||||
|
} else if wana_kana::utils::is_char_katakana(c) {
|
||||||
|
(
|
||||||
|
CharType::Katakana,
|
||||||
|
prev_type != CharType::Katakana,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else if wana_kana::utils::is_char_hiragana(c) {
|
||||||
|
(
|
||||||
|
CharType::Hiragana,
|
||||||
|
prev_type != CharType::Hiragana,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else if c.is_ascii() {
|
||||||
|
(CharType::Alpha, prev_type != CharType::Alpha, false, true)
|
||||||
|
} else if wana_kana::utils::is_char_kanji(c) {
|
||||||
|
if !kana_text.is_empty() {
|
||||||
|
hiragana.push_str(&convert_kana(&kana_text));
|
||||||
|
}
|
||||||
|
let (t, n) = convert_kanji(&text[i..], &kana_text, &dict);
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
kana_text = t;
|
||||||
|
for _ in 1..n {
|
||||||
|
char_indices.next();
|
||||||
|
}
|
||||||
|
(CharType::Kanji, false, false, false)
|
||||||
|
} else {
|
||||||
|
// Unknown kanji
|
||||||
|
kana_text.clear();
|
||||||
|
// TODO: FOR TESTING
|
||||||
|
hiragana.push_str("🯄");
|
||||||
|
(CharType::Kanji, true, false, false)
|
||||||
|
}
|
||||||
|
} else if matches!(c as u32, 0xf000..=0xfffd | 0x10000..=0x10ffd) {
|
||||||
|
// PUA: ignore and drop
|
||||||
|
if !kana_text.is_empty() {
|
||||||
|
hiragana.push_str(&convert_kana(&kana_text));
|
||||||
|
}
|
||||||
|
(prev_type, false, false, false)
|
||||||
|
} else {
|
||||||
|
(prev_type, true, true, true)
|
||||||
|
};
|
||||||
|
|
||||||
|
prev_type = output_flag.0;
|
||||||
|
|
||||||
|
if output_flag.1 && output_flag.2 {
|
||||||
|
kana_text.push(c);
|
||||||
|
hiragana.push_str(&convert_kana(&kana_text));
|
||||||
|
kana_text.clear()
|
||||||
|
} else if output_flag.1 && output_flag.3 {
|
||||||
|
if !kana_text.is_empty() {
|
||||||
|
hiragana.push_str(&convert_kana(&kana_text));
|
||||||
|
}
|
||||||
|
kana_text = c.to_string();
|
||||||
|
} else if output_flag.3 {
|
||||||
|
kana_text.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert last word
|
||||||
|
if !kana_text.is_empty() {
|
||||||
|
hiragana.push_str(&convert_kana(&kana_text));
|
||||||
|
}
|
||||||
|
|
||||||
|
hiragana
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_sym(c: char) -> bool {
|
||||||
|
matches!(c as u32,
|
||||||
|
0x3000..=0x3020 |
|
||||||
|
0x3030..=0x303F |
|
||||||
|
0x0391..=0x03A1 |
|
||||||
|
0x03A3..=0x03A9 |
|
||||||
|
0x03B1..=0x03C9 |
|
||||||
|
0x0410..= 0x044F |
|
||||||
|
0xFF01..=0xFF1A |
|
||||||
|
0x00A1..=0x00FF |
|
||||||
|
0xFF20..=0xFF5E |
|
||||||
|
0x0451 |
|
||||||
|
0x0401
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_kana(text: &str) -> String {
|
||||||
|
wana_kana::to_hiragana::to_hiragana_with_opt(
|
||||||
|
text,
|
||||||
|
wana_kana::Options {
|
||||||
|
use_obsolete_kana: false,
|
||||||
|
pass_romaji: true,
|
||||||
|
upcase_katakana: false,
|
||||||
|
imemode: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the leading kanji from the input string to hiragana
|
||||||
|
fn convert_kanji(text: &str, btext: &str, dict: &Records) -> (String, usize) {
|
||||||
|
let mut translation: Option<String> = None;
|
||||||
|
let mut i_c = 0;
|
||||||
|
let mut n_c = 0;
|
||||||
|
let mut char_indices = text.char_indices().peekable();
|
||||||
|
|
||||||
|
while let Some((i, c)) = char_indices.next() {
|
||||||
|
let kanji = &text[0..i + c.len_utf8()];
|
||||||
|
|
||||||
|
let this_tl = dict.get(kanji).and_then(|readings| {
|
||||||
|
readings
|
||||||
|
.iter()
|
||||||
|
.find_map(|(k, reading)| {
|
||||||
|
if k.is_empty() {
|
||||||
|
None
|
||||||
|
} else if let Some(cltr) = CLETTERS.get(&k.chars().next().unwrap_or_default()) {
|
||||||
|
char_indices.peek().and_then(|(_, next_c)| {
|
||||||
|
// Shortcut if the next character is not hiragana
|
||||||
|
if wana_kana::utils::is_char_hiragana(*next_c) {
|
||||||
|
if cltr.contains(&&next_c.to_string().as_str()) {
|
||||||
|
// Add the next character to the char count
|
||||||
|
i_c += 1;
|
||||||
|
let mut hira = reading.to_owned();
|
||||||
|
hira.push(*next_c);
|
||||||
|
return Some(hira);
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if wana_kana::is_hiragana::is_hiragana(&k) {
|
||||||
|
if btext.contains(reading) {
|
||||||
|
Some(reading.to_owned())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("invalid reading key")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| readings.get("").cloned())
|
||||||
|
});
|
||||||
|
|
||||||
|
i_c += 1;
|
||||||
|
if let Some(tl) = this_tl {
|
||||||
|
translation = Some(tl);
|
||||||
|
n_c = i_c;
|
||||||
|
}
|
||||||
|
if i_c >= 12 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
translation
|
||||||
|
.map(|tl| (tl.to_owned(), n_c))
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
Binary file not shown.
157
src/lib.rs
157
src/lib.rs
|
@ -12,6 +12,7 @@ use phfbin::PhfMap;
|
||||||
use types::{KanjiString, Readings};
|
use types::{KanjiString, Readings};
|
||||||
|
|
||||||
const KANJI_DICT: &[u8] = include_bytes!("./kanji_dict.bin");
|
const KANJI_DICT: &[u8] = include_bytes!("./kanji_dict.bin");
|
||||||
|
const MAX_KANJI_LEN: usize = 7;
|
||||||
|
|
||||||
static CLETTERS: phf::Map<u8, &[char]> = phf::phf_map!(
|
static CLETTERS: phf::Map<u8, &[char]> = phf::phf_map!(
|
||||||
b'a' => &['あ', 'ぁ', 'っ', 'わ', 'ゎ'],
|
b'a' => &['あ', 'ぁ', 'っ', 'わ', 'ゎ'],
|
||||||
|
@ -39,6 +40,20 @@ static CLETTERS: phf::Map<u8, &[char]> = phf::phf_map!(
|
||||||
b'v' => &['ゔ'],
|
b'v' => &['ゔ'],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ENDMARK: [char; 11] = [
|
||||||
|
')', ']', '!', '.', ',', '\u{3001}', '\u{3002}', '\u{ff1f}', '\u{ff10}', '\u{ff1e}', '\u{ff1c}',
|
||||||
|
];
|
||||||
|
const DASH_SYMBOLS: [char; 4] = ['\u{30FC}', '\u{2015}', '\u{2212}', '\u{FF70}'];
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum CharType {
|
||||||
|
Kanji,
|
||||||
|
Katakana,
|
||||||
|
Hiragana,
|
||||||
|
Symbol,
|
||||||
|
Alpha,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn convert(text: &str) -> KakasiResult {
|
pub fn convert(text: &str) -> KakasiResult {
|
||||||
let dict = PhfMap::new(KANJI_DICT);
|
let dict = PhfMap::new(KANJI_DICT);
|
||||||
|
|
||||||
|
@ -46,12 +61,131 @@ pub fn convert(text: &str) -> KakasiResult {
|
||||||
let text = text.nfkc().collect::<String>();
|
let text = text.nfkc().collect::<String>();
|
||||||
let text = convert_syn(&text);
|
let text = convert_syn(&text);
|
||||||
|
|
||||||
let hiragana = convert_kanji(&text, "", &dict).0;
|
let mut char_indices = text.char_indices();
|
||||||
let romaji = wana_kana::to_romaji::to_romaji(&hiragana);
|
let mut kana_text = String::new();
|
||||||
|
let mut prev_type = CharType::Kanji;
|
||||||
|
|
||||||
|
let mut hiragana = String::new();
|
||||||
|
let mut romaji = String::new();
|
||||||
|
|
||||||
|
let conv_kana_txt = |kana_text: &mut String, hiragana: &mut String, romaji: &mut String| {
|
||||||
|
if !kana_text.is_empty() {
|
||||||
|
let h = convert_kana(&kana_text);
|
||||||
|
hiragana.push_str(&h);
|
||||||
|
romaji.push_str(&wana_kana::to_romaji::to_romaji(&h));
|
||||||
|
romaji.push(' ');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// output_flag
|
||||||
|
// means (output buffer?, output text[i]?, copy to buffer and increment i?)
|
||||||
|
// possible (False, True, True), (True, False, False), (True, True, True)
|
||||||
|
// (False, False, True)
|
||||||
|
|
||||||
|
while let Some((i, c)) = char_indices.next() {
|
||||||
|
let output_flag = if ENDMARK.contains(&c) {
|
||||||
|
(CharType::Symbol, true, true, true)
|
||||||
|
} else if DASH_SYMBOLS.contains(&c) {
|
||||||
|
(prev_type, false, false, true)
|
||||||
|
} else if is_sym(c) {
|
||||||
|
if prev_type != CharType::Symbol {
|
||||||
|
(CharType::Symbol, true, false, true)
|
||||||
|
} else {
|
||||||
|
(CharType::Symbol, false, true, true)
|
||||||
|
}
|
||||||
|
} else if wana_kana::utils::is_char_katakana(c) {
|
||||||
|
(
|
||||||
|
CharType::Katakana,
|
||||||
|
prev_type != CharType::Katakana,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else if wana_kana::utils::is_char_hiragana(c) {
|
||||||
|
(
|
||||||
|
CharType::Hiragana,
|
||||||
|
prev_type != CharType::Hiragana,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else if c.is_ascii() {
|
||||||
|
(CharType::Alpha, prev_type != CharType::Alpha, false, true)
|
||||||
|
} else if wana_kana::utils::is_char_kanji(c) {
|
||||||
|
conv_kana_txt(&mut kana_text, &mut hiragana, &mut romaji);
|
||||||
|
let (t, n) = convert_kanji(&text[i..], &kana_text, &dict);
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
kana_text = t;
|
||||||
|
for _ in 1..n {
|
||||||
|
char_indices.next();
|
||||||
|
}
|
||||||
|
(CharType::Kanji, false, false, false)
|
||||||
|
} else {
|
||||||
|
// Unknown kanji
|
||||||
|
kana_text.clear();
|
||||||
|
// TODO: FOR TESTING
|
||||||
|
hiragana.push_str("🯄");
|
||||||
|
romaji.push_str("🯄");
|
||||||
|
(CharType::Kanji, true, false, false)
|
||||||
|
}
|
||||||
|
} else if matches!(c as u32, 0xf000..=0xfffd | 0x10000..=0x10ffd) {
|
||||||
|
// PUA: ignore and drop
|
||||||
|
conv_kana_txt(&mut kana_text, &mut hiragana, &mut romaji);
|
||||||
|
kana_text.clear();
|
||||||
|
(prev_type, false, false, false)
|
||||||
|
} else {
|
||||||
|
(prev_type, true, true, true)
|
||||||
|
};
|
||||||
|
|
||||||
|
prev_type = output_flag.0;
|
||||||
|
|
||||||
|
if output_flag.1 && output_flag.2 {
|
||||||
|
kana_text.push(c);
|
||||||
|
conv_kana_txt(&mut kana_text, &mut hiragana, &mut romaji);
|
||||||
|
kana_text.clear()
|
||||||
|
} else if output_flag.1 && output_flag.3 {
|
||||||
|
conv_kana_txt(&mut kana_text, &mut hiragana, &mut romaji);
|
||||||
|
kana_text = c.to_string();
|
||||||
|
} else if output_flag.3 {
|
||||||
|
kana_text.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert last word
|
||||||
|
conv_kana_txt(&mut kana_text, &mut hiragana, &mut romaji);
|
||||||
|
// Remove trailing space
|
||||||
|
romaji.pop();
|
||||||
|
|
||||||
KakasiResult { hiragana, romaji }
|
KakasiResult { hiragana, romaji }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_sym(c: char) -> bool {
|
||||||
|
matches!(c as u32,
|
||||||
|
0x3000..=0x3020 |
|
||||||
|
0x3030..=0x303F |
|
||||||
|
0x0391..=0x03A1 |
|
||||||
|
0x03A3..=0x03A9 |
|
||||||
|
0x03B1..=0x03C9 |
|
||||||
|
0x0410..= 0x044F |
|
||||||
|
0xFF01..=0xFF1A |
|
||||||
|
0x00A1..=0x00FF |
|
||||||
|
0xFF20..=0xFF5E |
|
||||||
|
0x0451 |
|
||||||
|
0x0401
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_kana(text: &str) -> String {
|
||||||
|
wana_kana::to_hiragana::to_hiragana_with_opt(
|
||||||
|
text,
|
||||||
|
wana_kana::Options {
|
||||||
|
use_obsolete_kana: false,
|
||||||
|
pass_romaji: true,
|
||||||
|
upcase_katakana: false,
|
||||||
|
imemode: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert the leading kanji from the input string to hiragana
|
/// Convert the leading kanji from the input string to hiragana
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -61,7 +195,7 @@ pub fn convert(text: &str) -> KakasiResult {
|
||||||
/// The input needs to be NFKC-normalized and synonymous kanji need to be
|
/// The input needs to be NFKC-normalized and synonymous kanji need to be
|
||||||
/// replaced using [`convert_syn`].
|
/// replaced using [`convert_syn`].
|
||||||
///
|
///
|
||||||
/// * `btext` -
|
/// * `btext` - Buffer string (leading kana)
|
||||||
///
|
///
|
||||||
/// # Return
|
/// # Return
|
||||||
///
|
///
|
||||||
|
@ -69,6 +203,7 @@ pub fn convert(text: &str) -> KakasiResult {
|
||||||
/// * `1` - Number of converted chars from the input string
|
/// * `1` - Number of converted chars from the input string
|
||||||
fn convert_kanji(text: &str, btext: &str, dict: &PhfMap) -> (String, usize) {
|
fn convert_kanji(text: &str, btext: &str, dict: &PhfMap) -> (String, usize) {
|
||||||
let mut translation = None;
|
let mut translation = None;
|
||||||
|
let mut i_c = 0;
|
||||||
let mut n_c = 0;
|
let mut n_c = 0;
|
||||||
let mut char_indices = text.char_indices().peekable();
|
let mut char_indices = text.char_indices().peekable();
|
||||||
|
|
||||||
|
@ -87,7 +222,7 @@ fn convert_kanji(text: &str, btext: &str, dict: &PhfMap) -> (String, usize) {
|
||||||
CLETTERS.get(&ch).and_then(|cltr| {
|
CLETTERS.get(&ch).and_then(|cltr| {
|
||||||
if cltr.contains(next_c) {
|
if cltr.contains(next_c) {
|
||||||
// Add the next character to the char count
|
// Add the next character to the char count
|
||||||
n_c += 1;
|
i_c += 1;
|
||||||
hira.push(*next_c);
|
hira.push(*next_c);
|
||||||
Some(hira)
|
Some(hira)
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,11 +244,14 @@ fn convert_kanji(text: &str, btext: &str, dict: &PhfMap) -> (String, usize) {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
match this_tl {
|
i_c += 1;
|
||||||
Some(this_tl) => translation = Some(this_tl),
|
if let Some(tl) = this_tl {
|
||||||
None => break,
|
translation = Some(tl);
|
||||||
|
n_c = i_c;
|
||||||
|
}
|
||||||
|
if i_c >= MAX_KANJI_LEN {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
n_c += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
translation
|
translation
|
||||||
|
@ -165,6 +303,9 @@ mod tests {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case("会っAbc", "あっ", 2)]
|
#[case("会っAbc", "あっ", 2)]
|
||||||
|
#[case("渋谷", "しぶや", 2)]
|
||||||
|
// #[case("渋谷公会堂", "しぶやこうかいどう", 5)]
|
||||||
|
// #[case("家畜衛生試験場", "かちくえいせいしけんじょう", 7)]
|
||||||
fn t_convert_kanji(#[case] text: &str, #[case] expect: &str, #[case] expect_n: usize) {
|
fn t_convert_kanji(#[case] text: &str, #[case] expect: &str, #[case] expect_n: usize) {
|
||||||
let dict = PhfMap::new(KANJI_DICT);
|
let dict = PhfMap::new(KANJI_DICT);
|
||||||
let (res, n) = convert_kanji(text, "", &dict);
|
let (res, n) = convert_kanji(text, "", &dict);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
for line in std::io::stdin().lines() {
|
for line in std::io::stdin().lines() {
|
||||||
let res = kakasi::convert(&line.unwrap());
|
let res = kakasi::convert(&line.unwrap());
|
||||||
println!("{} - {}", res.hiragana, res.romaji);
|
println!("{}\n{}\n\n", res.hiragana, res.romaji);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue