braillify 2.0.0

Rust 기반 크로스플랫폼 한국어 점역 라이브러리
Documentation
use once_cell::sync::Lazy;
use regex::Regex;

use crate::fraction;
use crate::rules::token::{Token, WordMeta, WordToken};
use crate::rules::token_rule::{TokenAction, TokenPhase, TokenRule};

static FRACTION_REGEX: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"^(\d+)\/(\d+)").expect("Failed to compile FRACTION_REGEX"));

pub struct InlineFractionRule;

impl TokenRule for InlineFractionRule {
    fn phase(&self) -> TokenPhase {
        TokenPhase::FractionDetection
    }

    fn priority(&self) -> u16 {
        120
    }

    fn apply<'a>(
        &self,
        tokens: &[Token<'a>],
        index: usize,
        _state: &mut crate::rules::context::EncoderState,
    ) -> Result<TokenAction<'a>, String> {
        let Some(Token::Word(word)) = tokens.get(index) else {
            return Ok(TokenAction::Noop);
        };

        let chars = &word.chars;
        let word_len = chars.len();

        for (i, ch) in chars.iter().enumerate() {
            if !ch.is_ascii_digit() {
                continue;
            }

            let remaining: String = chars[i..].iter().collect();
            let Some(captures) = FRACTION_REGEX.captures(&remaining) else {
                continue;
            };

            let numerator = &captures[1];
            let denominator = &captures[2];
            let match_len = captures[0].len();
            let k = i + match_len;
            let is_date_or_range = (numerator.len() > 1 || denominator.len() > 1)
                || (k < word_len && chars[k] == '/')
                || (k < word_len && chars[k] == '~');

            if is_date_or_range {
                continue;
            }

            let mut replacement = Vec::new();

            if i > 0 {
                let prefix: String = chars[..i].iter().collect();
                let prefix_chars: Vec<char> = prefix.chars().collect();
                replacement.push(Token::Word(WordToken {
                    text: std::borrow::Cow::Owned(prefix),
                    chars: prefix_chars.clone(),
                    meta: WordMeta::from_chars(&prefix_chars),
                }));
            }

            replacement.push(Token::PreEncoded(fraction::encode_fraction_in_context(
                numerator,
                denominator,
            )?));

            if k < word_len {
                let suffix: String = chars[k..].iter().collect();
                let suffix_chars: Vec<char> = suffix.chars().collect();
                replacement.push(Token::Word(WordToken {
                    text: std::borrow::Cow::Owned(suffix),
                    chars: suffix_chars.clone(),
                    meta: WordMeta::from_chars(&suffix_chars),
                }));
            }

            return Ok(TokenAction::ReplaceMany(replacement));
        }

        Ok(TokenAction::Noop)
    }
}