braillify 2.0.0

Rust 기반 크로스플랫폼 한국어 점역 라이브러리
Documentation
use phf::phf_map;

#[derive(Debug, PartialEq)]
pub enum KoreanChar {
    Choseong(char),
    Jongseong(char),
    Jungseong(char),
}
impl KoreanChar {
    pub fn get_char(&self) -> char {
        match self {
            KoreanChar::Choseong(c) => *c,
            KoreanChar::Jongseong(c) => *c,
            KoreanChar::Jungseong(c) => *c,
        }
    }
}

// ㄱ, ㄲ, ㄳ, ㄴ, ㄵ, ㄶ, ㄷ, ㄸ, ㄹ, ㄺ, ㄻ, ㄼ, ㄽ, ㄾ, ㄿ, ㅀ, ㅁ, ㅂ, ㅃ, ㅄ, ㅅ, ㅆ, ㅇ, ㅈ, ㅉ, ㅊ, ㅋ, ㅌ, ㅍ, ㅎ
pub static KOREAN_JAUEM_MAP: phf::Map<char, (char, Option<char>)> = phf_map! {
    '' => ('', None),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', None),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', None),
    '' => ('', Some('')),
    '' => ('', None),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', None),
    '' => ('', None),
    '' => ('', Some('')),
    '' => ('', Some('')),
    '' => ('', None),
    '' => ('', Some('')),
    '' => ('', None),
    '' => ('', None),
    '' => ('', Some('')),
    '' => ('', None),
    '' => ('', None),
    '' => ('', None),
    '' => ('', None),
    '' => ('', None),
};

/// 자음을 분리합니다.
pub fn split_korean_jauem(text: char) -> Result<(char, Option<char>), String> {
    if let Some((cho, jong)) = KOREAN_JAUEM_MAP.get(&text) {
        return Ok((*cho, *jong));
    }
    Err("Invalid Korean character".to_string())
}
pub fn split_korean_char(text: char) -> Result<Vec<KoreanChar>, String> {
    // check korean char
    let code = text as u32;
    if (0x3131..=0x314E).contains(&code) {
        return Ok(vec![KoreanChar::Choseong(text)]);
    }
    if (0x314F..=0x3163).contains(&code) {
        return Ok(vec![KoreanChar::Jungseong(text)]);
    }
    if !(0xAC00..=0xD7A3).contains(&code) {
        return Err("Invalid Korean character".to_string());
    }

    const CHOSEONG: [char; 19] = [
        '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
        '', '', '', '',
    ];
    const JUNGSEONG: [char; 21] = [
        '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
        '', '', '', '', '', '',
    ];
    const JONGSEONG: [char; 28] = [
        ' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
        '', '', '', '', '', '', '', '', '', '', '', '', '',
    ];

    let code = text as u32;

    let uni = code - 0xAC00;
    let fn_idx = (uni / 588) as usize;
    let sn_idx = ((uni - (fn_idx as u32 * 588)) / 28) as usize;
    let tn_idx = (uni % 28) as usize;

    let mut result = Vec::new();
    result.push(KoreanChar::Choseong(CHOSEONG[fn_idx]));
    result.push(KoreanChar::Jungseong(JUNGSEONG[sn_idx]));
    if JONGSEONG[tn_idx] != ' ' {
        result.push(KoreanChar::Jongseong(JONGSEONG[tn_idx]));
    }

    Ok(result)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_split() {
        assert_eq!(
            split_korean_char(''),
            Ok(vec![
                KoreanChar::Choseong(''),
                KoreanChar::Jungseong(''),
                KoreanChar::Jongseong('')
            ])
        );
        assert_eq!(
            split_korean_char(''),
            Ok(vec![
                KoreanChar::Choseong(''),
                KoreanChar::Jungseong(''),
                KoreanChar::Jongseong('')
            ])
        );
        assert_eq!(
            split_korean_char(''),
            Ok(vec![
                KoreanChar::Choseong(''),
                KoreanChar::Jungseong(''),
                KoreanChar::Jongseong('')
            ])
        );
        assert_eq!(
            split_korean_char(''),
            Ok(vec![
                KoreanChar::Choseong(''),
                KoreanChar::Jungseong(''),
                KoreanChar::Jongseong('')
            ])
        );
        assert_eq!(
            split_korean_char(''),
            Ok(vec![
                KoreanChar::Choseong(''),
                KoreanChar::Jungseong(''),
                KoreanChar::Jongseong('')
            ])
        );

        assert_eq!(
            split_korean_char(''),
            Ok(vec![
                KoreanChar::Choseong(''),
                KoreanChar::Jungseong(''),
            ])
        );

        assert_eq!(
            split_korean_char(''),
            Ok(vec![
                KoreanChar::Choseong(''),
                KoreanChar::Jungseong(''),
            ])
        );
    }

    #[test]
    fn test_split_choseong() {
        for c in [
            '', '', '', '', '', '', '', '', '', '', '', '',
        ] {
            assert_eq!(split_korean_char(c), Ok(vec![KoreanChar::Choseong(c),]));
        }
    }

    #[test]
    fn test_split_jungseong() {
        for c in [
            '', '', '', '', '', '', '', '', '', '', '', '', '', '',
            '', '', '', '', '', '', '',
        ] {
            assert_eq!(split_korean_char(c), Ok(vec![KoreanChar::Jungseong(c),]));
        }
    }

    #[test]
    fn test_split_wrong() {
        assert_eq!(
            split_korean_char('a'),
            Err("Invalid Korean character".to_string())
        );
        assert_eq!(
            split_korean_char('1'),
            Err("Invalid Korean character".to_string())
        );
    }
}