use crate::{NJDNode, NJD};
use jpreprocess_core::pron;
mod builder;
mod score;
const UNKNOWN_DICT_DIGITS: phf::Map<char, &'static str> = phf::phf_map! {
'0' => "0,名詞,数,*,*,*,*,0,ゼロ,ゼロ,1/2,C3",
'1' => "1,名詞,数,*,*,*,*,1,イチ,イチ,2/2,C3",
'2' => "2,名詞,数,*,*,*,*,2,ニ,ニ,1/1,C3",
'3' => "3,名詞,数,*,*,*,*,3,サン,サン,0/2,C3",
'4' => "4,名詞,数,*,*,*,*,4,ヨン,ヨン,1/2,C1",
'5' => "5,名詞,数,*,*,*,*,5,ゴ,ゴ,1/1,C3",
'6' => "6,名詞,数,*,*,*,*,6,ロク,ロク,2/2,C3",
'7' => "7,名詞,数,*,*,*,*,7,ナナ,ナナ,1/2,C3",
'8' => "8,名詞,数,*,*,*,*,8,ハチ,ハチ,2/2,C3",
'9' => "9,名詞,数,*,*,*,*,9,キュウ,キュー,1/2,C3",
};
const DIGIT_NORMALIZE: phf::Map<&'static str, &'static str> = phf::phf_map! {
"○" => "〇",
"1" => "一",
"2" => "二",
"3" => "三",
"4" => "四",
"5" => "五",
"6" => "六",
"7" => "七",
"8" => "八",
"9" => "九",
"一" => "一",
"二" => "二",
"三" => "三",
"四" => "四",
"五" => "五",
"六" => "六",
"七" => "七",
"八" => "八",
"九" => "九",
"いち" => "一",
"に" => "二",
"さん" => "三",
"よん" => "四",
"ご" => "五",
"ろく" => "六",
"なな" => "七",
"はち" => "八",
"きゅう" => "九",
"〇" => "〇",
"0" => "0",
"壱" => "一",
"弐" => "二",
"貳" => "二",
"ニ" => "二",
"参" => "三",
"し" => "四",
"しち" => "七",
"く" => "九"
};
const NUMERAL_LIST2: &[&str] = &[
"",
"十,名詞,数,*,*,*,*,十,ジュウ,ジュー,1/2,*",
"百,名詞,数,*,*,*,*,百,ヒャク,ヒャク,2/2,*",
"千,名詞,数,*,*,*,*,千,セン,セン,1/2,*",
];
const NUMERAL_LIST3: &[&str] = &[
"",
"万,名詞,数,*,*,*,*,万,マン,マン,1/2,*",
"億,名詞,数,*,*,*,*,億,オク,オク,1/2,*",
"兆,名詞,数,*,*,*,*,兆,チョウ,チョー,1/2,C3",
"京,名詞,数,*,*,*,*,京,ケイ,ケー,1/2,*",
"垓,名詞,数,*,*,*,*,垓,ガイ,ガイ,1/2,*",
"𥝱,名詞,数,*,*,*,*,𥝱,ジョ,ジョ,1/1,*",
"穣,名詞,数,*,*,*,*,穣,ジョウ,ジョー,1/2,*",
"溝,名詞,数,*,*,*,*,溝,コウ,コウ,1/2,*",
"澗,名詞,数,*,*,*,*,澗,カン,カン,1/2,*",
"正,名詞,数,*,*,*,*,正,セイ,セー,1/2,*",
"載,名詞,数,*,*,*,*,載,サイ,サイ,1/2,*",
"極,名詞,数,*,*,*,*,極,ゴク,ゴク,1/2,*",
"恒河沙,名詞,数,*,*,*,*,恒河沙,ゴウガシャ,ゴウガシャ,1/4,*",
"阿僧祇,名詞,数,*,*,*,*,阿僧祇,アソウギ,アソーギ,2/4,*",
"那由他,名詞,数,*,*,*,*,那由他,ナユタ,ナユタ,1/3,*",
"不可思議,名詞,数,*,*,*,*,不可思議,フカシギ,フカシギ,2/4,*",
"無量大数,名詞,数,*,*,*,*,無量大数,ムリョウタイスウ,ムリョータイスー,6/7,*",
];
pub fn njd_digit_sequence(njd: &mut NJD) {
{
let mut i = 0;
while let Some(node) = njd.nodes.get(i) {
'unk_digits: {
if !node.get_pron().is_touten() || !node.get_pos().is_kazu() {
break 'unk_digits;
}
let mut converted_nodes = Vec::with_capacity(node.get_string().chars().count());
for c in node.get_string().chars() {
if let Some(node_str) = UNKNOWN_DICT_DIGITS.get(&c) {
converted_nodes.push(NJDNode::new_single(node_str));
} else {
break 'unk_digits;
}
}
njd.nodes.splice(i..=i, converted_nodes);
}
i += 1;
}
}
for node in &mut njd.nodes {
if node.get_string() != "*" && node.get_pos().is_kazu() {
if let Some(replace) = DIGIT_NORMALIZE.get(node.get_string()) {
node.replace_string(replace);
}
}
}
let mut sequences = builder::from_njd(njd);
let mut offset = 0;
for seq in &mut sequences {
offset += seq.convert(njd, offset);
}
njd.remove_silent_node();
}
#[derive(Debug)]
struct DigitSequence {
start: usize,
end: usize,
digits: Vec<u8>,
is_numerical_reading: Option<bool>,
}
impl DigitSequence {
pub fn new(
start: usize,
end: usize,
digits: Vec<u8>,
is_numerical_reading: Option<bool>,
) -> Self {
Self {
start,
end,
digits,
is_numerical_reading,
}
}
pub fn estimate_numerical_reading(&mut self, njd: &NJD) {
if self.is_numerical_reading.is_none() {
self.is_numerical_reading = Some(score::score(njd, self.start, self.end) >= 0);
}
}
pub fn convert(&mut self, njd: &mut NJD, offset: i64) -> i64 {
self.start = (self.start as i64 + offset) as usize;
self.end = (self.end as i64 + offset) as usize;
if self.is_numerical_reading.unwrap() {
self.convert_for_numerical_reading(njd)
} else {
self.convert_for_non_numerical_reading(njd);
0
}
}
fn convert_for_non_numerical_reading(&self, njd: &mut NJD) {
for (i, (node, digit)) in njd.nodes[self.start..]
.iter_mut()
.zip(self.digits.iter())
.enumerate()
{
match *digit {
0 => {
node.set_pron(pron!([Ze, Ro], 1));
}
2 => {
node.set_pron(pron!([Ni, Long], 1));
}
5 => {
node.set_pron(pron!([Go, Long], 1));
}
_ => (),
}
node.unset_chain_rule();
if i % 2 == 0 {
node.set_chain_flag(false);
if i != self.digits.len() - 1 {
node.get_pron_mut().set_accent(3);
}
} else {
node.set_chain_flag(true);
}
}
}
fn convert_for_numerical_reading(&self, njd: &mut NJD) -> i64 {
let mut offset_comma = 0;
let mut idx = 0;
njd.nodes.retain(|node| {
if idx < self.start || self.end < idx {
idx += 1;
return true;
} else {
idx += 1;
}
if node.get_string() == "," {
offset_comma += 1;
false
} else {
true
}
});
if self.digits.len() > NUMERAL_LIST3.len() * 4 {
return offset_comma;
}
let mut have_digit_in_block = false;
let mut offset = 0;
for (i, digit) in self.digits.iter().enumerate() {
let nodes_index = self.start + i + offset;
let rev_index = self.digits.len() - i - 1;
if *digit == 0 {
let node = &mut njd.nodes[nodes_index];
node.reset();
} else {
have_digit_in_block = true;
}
if rev_index.is_multiple_of(4) {
if have_digit_in_block && rev_index > 0 {
njd.nodes.insert(
nodes_index + 1,
NJDNode::new_single(NUMERAL_LIST3[rev_index / 4]),
);
offset += 1;
}
have_digit_in_block = false;
} else {
match *digit {
0 => (),
1 => njd.nodes[nodes_index] = NJDNode::new_single(NUMERAL_LIST2[rev_index % 4]),
_ => {
njd.nodes.insert(
nodes_index + 1,
NJDNode::new_single(NUMERAL_LIST2[rev_index % 4]),
);
offset += 1;
}
}
}
}
offset as i64 - offset_comma
}
}