Spaces:
Sleeping
Sleeping
| from typing import Any | |
| import fugashi | |
| from .config import Config | |
| try: | |
| # SudachiPy があれば直接利用してモードCを使用 | |
| from sudachipy import dictionary as sudachi_dictionary | |
| from sudachipy import tokenizer as sudachi_tokenizer | |
| _SUDACHI_AVAILABLE = True | |
| except Exception: | |
| _SUDACHI_AVAILABLE = False | |
| class WordCounter: | |
| """単語数を数えるクラス(SudachiPyがあれば mode=C、なければfugashi)""" | |
| def __init__(self, tokenizer: Any = None): | |
| """ | |
| 初期化 | |
| Args: | |
| tokenizer: fugashiトークナイザー(Noneの場合はデフォルトを使用) | |
| """ | |
| # 優先順位: 引数tokenizer > SudachiPy > fugashi(GenericTagger) | |
| self._use_sudachi = False | |
| self._sudachi_mode = None | |
| if tokenizer is not None: | |
| self.tokenizer = tokenizer | |
| elif _SUDACHI_AVAILABLE: | |
| # SudachiPyの辞書は自動で同梱辞書を参照(sudachidict_core) | |
| # 外部設定不要。SplitMode.C を使用 | |
| self._use_sudachi = True | |
| self.tokenizer = sudachi_dictionary.Dictionary().create() | |
| self._sudachi_mode = sudachi_tokenizer.Tokenizer.SplitMode.C | |
| else: | |
| # fugashi (MeCab) フォールバック | |
| fugashi_args = Config.get_fugashi_args() | |
| if fugashi_args: | |
| self.tokenizer = fugashi.GenericTagger(fugashi_args) | |
| else: | |
| # 引数なしでデフォルト設定を使用 | |
| self.tokenizer = fugashi.GenericTagger() | |
| def count_words(self, text: str) -> int: | |
| """ | |
| テキストの単語数をカウント | |
| Args: | |
| text: カウントするテキスト | |
| Returns: | |
| int: 単語数 | |
| """ | |
| if not text: | |
| return 0 | |
| try: | |
| # fugashiで形態素解析して単語数をカウント | |
| if self._use_sudachi: | |
| tokens = self.tokenizer.tokenize(text, self._sudachi_mode) | |
| return len(tokens) | |
| else: | |
| tokens = self.tokenizer(text) | |
| return len(tokens) | |
| except Exception as e: | |
| print(f"単語数カウントエラー: {e}") | |
| # フォールバック: 空白で分割 | |
| return len(text.split()) | |
| def is_word_boundary(self, text: str, position: int) -> bool: | |
| """ | |
| 指定位置が単語境界かどうかを判定 | |
| Args: | |
| text: テキスト | |
| position: 位置(負の値で末尾から指定可能、-1は末尾) | |
| Returns: | |
| bool: 単語境界かどうか | |
| """ | |
| if not text: | |
| return True | |
| # 負のインデックスを正のインデックスに変換 | |
| if position < 0: | |
| position = len(text) + position | |
| if position >= len(text): | |
| return True | |
| try: | |
| # fugashiで形態素解析 | |
| if self._use_sudachi: | |
| tokens = self.tokenizer.tokenize(text, self._sudachi_mode) | |
| surfaces = [m.surface() for m in tokens] | |
| else: | |
| tokens = self.tokenizer(text) | |
| surfaces = [m.surface for m in tokens] | |
| current_pos = 0 | |
| for surface in surfaces: | |
| token_length = len(surface) | |
| if current_pos <= position < current_pos + token_length: | |
| return False | |
| if position == current_pos + token_length: | |
| return True | |
| current_pos += token_length | |
| return True | |
| except Exception as e: | |
| print(f"境界判定エラー: {e}") | |
| # フォールバック: 空白文字で判定 | |
| return position < len(text) and text[position].isspace() | |