libs.utils.textutil
libs/utils/textutil.py
1""" 2libs/utils/textutil.py 3""" 4 5import os 6from enum import Enum, auto 7from math import ceil, floor 8from typing import TYPE_CHECKING, Any 9 10import libs.global_value as g 11 12if TYPE_CHECKING: 13 from pathlib import Path 14 15 16class ConversionType(Enum): 17 """変換タイプ""" 18 19 HtoZ = auto() 20 """半角文字を全角文字に変換(数字のみ)""" 21 ZtoH = auto() 22 """全角文字を半角文字に変換(数字のみ)""" 23 HtoK = auto() 24 """ひらがなをカタカナに変換""" 25 KtoH = auto() 26 """カタカナをひらがなに変換""" 27 28 29def str_conv(text: str, kind: ConversionType) -> str: 30 """ 31 文字列変換 32 33 Args: 34 text (str): 変換対象文字列 35 kind (ConversionType): 変換種類 36 37 Returns: 38 str: 変換後の文字列 39 40 """ 41 zen = "".join(chr(0xFF10 + i) for i in range(10)) 42 han = "".join(chr(0x30 + i) for i in range(10)) 43 hira = "".join(chr(0x3041 + i) for i in range(86)) 44 kana = "".join(chr(0x30A1 + i) for i in range(86)) 45 46 match kind: 47 case ConversionType.HtoZ: 48 trans_table = str.maketrans(han, zen) 49 case ConversionType.ZtoH: 50 trans_table = str.maketrans(zen, han) 51 case ConversionType.HtoK: 52 trans_table = str.maketrans(hira, kana) 53 case ConversionType.KtoH: 54 trans_table = str.maketrans(kana, hira) 55 case _: 56 return text 57 58 return text.translate(trans_table) 59 60 61def save_file_path(filename: str, delete: bool = False) -> "Path": 62 """ 63 保存ファイルのフルパスを取得 64 65 Args: 66 filename (str): デフォルトファイル名 67 delete (bool, optional): 生成済みファイルを削除. Defaults to False. 68 69 Returns: 70 Path: 保存ファイルパス 71 72 """ 73 _, file_ext = os.path.splitext(filename) 74 file_name = f"{g.params.filename}{file_ext}" if g.params.filename else f"{filename}" 75 file_path = g.cfg.setting.work_dir / file_name 76 77 if file_path.exists() and delete: 78 os.remove(file_path) 79 80 return file_path 81 82 83def split_balanced(data: list[list[Any]], target_size: int, tolerance: float = 0.15) -> list[list[Any]]: 84 """ 85 リストデータを指定個数で分割 86 87 Args: 88 data (list[list[Any]]): 対象データ 89 target_size (int): 分割サイズ 90 tolerance (float, optional): 個数誤差. Defaults to 0.15. 91 92 Returns: 93 list[list[Any]]: 分割したリスト 94 95 """ 96 # 分割サイズに0が指定されている場合は何もしない 97 if not target_size: 98 return data 99 100 n = len(data) 101 if n == 0: 102 return [] 103 104 min_size = int(target_size * (1 - tolerance)) 105 max_size = int(target_size * (1 + tolerance)) 106 107 # 最小ブロック数の候補を計算 108 min_blocks = ceil(n / max_size) 109 max_blocks = floor(n / min_size) 110 111 # 許容範囲内でブロック数を決める(なるべく少ない) 112 for num_blocks in range(min_blocks, max_blocks + 1): 113 size = n / num_blocks 114 if min_size <= size <= max_size: 115 break 116 else: 117 # 条件を満たすブロック数がない場合は単純均等割り 118 num_blocks = ceil(n / target_size) 119 120 # 実際の分割処理 121 base_size = n // num_blocks 122 remainder = n % num_blocks 123 124 result: list[list[Any]] = [] 125 start = 0 126 for i in range(num_blocks): 127 end = start + base_size + (1 if i < remainder else 0) 128 result.append(data[start:end]) 129 start = end 130 131 return result 132 133 134def split_text_blocks(text: str, limit: int = 2000) -> list[str]: 135 """ 136 指定文字数でテキストを行単位で分割してリストにする 137 138 Args: 139 text (str): 対象文字列 140 limit (int, optional): 分割文字数. Defaults to 2000. 141 142 Returns: 143 list[str]: 分割リスト 144 145 """ 146 blocks: list[str] = [] 147 current_data = "" 148 buffer_data = "" 149 in_code = False 150 min_gap_after_code_start = 10 151 lines_count = 0 152 153 for _, line in enumerate(text.splitlines(keepends=True)): 154 stripped = line.strip() 155 buffer_data += line 156 157 # --- コードブロック開始/終了検出 --- 158 if stripped.startswith("```"): 159 in_code = not in_code 160 if not in_code: 161 current_data += buffer_data 162 buffer_data = "" 163 continue 164 165 lines_count += 1 if in_code else 0 166 167 # --- 文字数チェック --- 168 if len(current_data + buffer_data) > limit: 169 if lines_count > min_gap_after_code_start: 170 if in_code: 171 blocks.append(current_data + buffer_data + "```\n") 172 buffer_data = "```\n" 173 else: 174 blocks.append(current_data + buffer_data) 175 buffer_data = "" 176 else: 177 blocks.append(current_data) # 先頭の改行は削除されてしまう 178 current_data = "" 179 180 return blocks
class
ConversionType(enum.Enum):
17class ConversionType(Enum): 18 """変換タイプ""" 19 20 HtoZ = auto() 21 """半角文字を全角文字に変換(数字のみ)""" 22 ZtoH = auto() 23 """全角文字を半角文字に変換(数字のみ)""" 24 HtoK = auto() 25 """ひらがなをカタカナに変換""" 26 KtoH = auto() 27 """カタカナをひらがなに変換"""
変換タイプ
30def str_conv(text: str, kind: ConversionType) -> str: 31 """ 32 文字列変換 33 34 Args: 35 text (str): 変換対象文字列 36 kind (ConversionType): 変換種類 37 38 Returns: 39 str: 変換後の文字列 40 41 """ 42 zen = "".join(chr(0xFF10 + i) for i in range(10)) 43 han = "".join(chr(0x30 + i) for i in range(10)) 44 hira = "".join(chr(0x3041 + i) for i in range(86)) 45 kana = "".join(chr(0x30A1 + i) for i in range(86)) 46 47 match kind: 48 case ConversionType.HtoZ: 49 trans_table = str.maketrans(han, zen) 50 case ConversionType.ZtoH: 51 trans_table = str.maketrans(zen, han) 52 case ConversionType.HtoK: 53 trans_table = str.maketrans(hira, kana) 54 case ConversionType.KtoH: 55 trans_table = str.maketrans(kana, hira) 56 case _: 57 return text 58 59 return text.translate(trans_table)
文字列変換
Arguments:
- text (str): 変換対象文字列
- kind (ConversionType): 変換種類
Returns:
str: 変換後の文字列
def
save_file_path(filename: str, delete: bool = False) -> pathlib.Path:
62def save_file_path(filename: str, delete: bool = False) -> "Path": 63 """ 64 保存ファイルのフルパスを取得 65 66 Args: 67 filename (str): デフォルトファイル名 68 delete (bool, optional): 生成済みファイルを削除. Defaults to False. 69 70 Returns: 71 Path: 保存ファイルパス 72 73 """ 74 _, file_ext = os.path.splitext(filename) 75 file_name = f"{g.params.filename}{file_ext}" if g.params.filename else f"{filename}" 76 file_path = g.cfg.setting.work_dir / file_name 77 78 if file_path.exists() and delete: 79 os.remove(file_path) 80 81 return file_path
保存ファイルのフルパスを取得
Arguments:
- filename (str): デフォルトファイル名
- delete (bool, optional): 生成済みファイルを削除. Defaults to False.
Returns:
Path: 保存ファイルパス
def
split_balanced( data: list[list[typing.Any]], target_size: int, tolerance: float = 0.15) -> list[list[typing.Any]]:
84def split_balanced(data: list[list[Any]], target_size: int, tolerance: float = 0.15) -> list[list[Any]]: 85 """ 86 リストデータを指定個数で分割 87 88 Args: 89 data (list[list[Any]]): 対象データ 90 target_size (int): 分割サイズ 91 tolerance (float, optional): 個数誤差. Defaults to 0.15. 92 93 Returns: 94 list[list[Any]]: 分割したリスト 95 96 """ 97 # 分割サイズに0が指定されている場合は何もしない 98 if not target_size: 99 return data 100 101 n = len(data) 102 if n == 0: 103 return [] 104 105 min_size = int(target_size * (1 - tolerance)) 106 max_size = int(target_size * (1 + tolerance)) 107 108 # 最小ブロック数の候補を計算 109 min_blocks = ceil(n / max_size) 110 max_blocks = floor(n / min_size) 111 112 # 許容範囲内でブロック数を決める(なるべく少ない) 113 for num_blocks in range(min_blocks, max_blocks + 1): 114 size = n / num_blocks 115 if min_size <= size <= max_size: 116 break 117 else: 118 # 条件を満たすブロック数がない場合は単純均等割り 119 num_blocks = ceil(n / target_size) 120 121 # 実際の分割処理 122 base_size = n // num_blocks 123 remainder = n % num_blocks 124 125 result: list[list[Any]] = [] 126 start = 0 127 for i in range(num_blocks): 128 end = start + base_size + (1 if i < remainder else 0) 129 result.append(data[start:end]) 130 start = end 131 132 return result
リストデータを指定個数で分割
Arguments:
- data (list[list[Any]]): 対象データ
- target_size (int): 分割サイズ
- tolerance (float, optional): 個数誤差. Defaults to 0.15.
Returns:
list[list[Any]]: 分割したリスト
def
split_text_blocks(text: str, limit: int = 2000) -> list[str]:
135def split_text_blocks(text: str, limit: int = 2000) -> list[str]: 136 """ 137 指定文字数でテキストを行単位で分割してリストにする 138 139 Args: 140 text (str): 対象文字列 141 limit (int, optional): 分割文字数. Defaults to 2000. 142 143 Returns: 144 list[str]: 分割リスト 145 146 """ 147 blocks: list[str] = [] 148 current_data = "" 149 buffer_data = "" 150 in_code = False 151 min_gap_after_code_start = 10 152 lines_count = 0 153 154 for _, line in enumerate(text.splitlines(keepends=True)): 155 stripped = line.strip() 156 buffer_data += line 157 158 # --- コードブロック開始/終了検出 --- 159 if stripped.startswith("```"): 160 in_code = not in_code 161 if not in_code: 162 current_data += buffer_data 163 buffer_data = "" 164 continue 165 166 lines_count += 1 if in_code else 0 167 168 # --- 文字数チェック --- 169 if len(current_data + buffer_data) > limit: 170 if lines_count > min_gap_after_code_start: 171 if in_code: 172 blocks.append(current_data + buffer_data + "```\n") 173 buffer_data = "```\n" 174 else: 175 blocks.append(current_data + buffer_data) 176 buffer_data = "" 177 else: 178 blocks.append(current_data) # 先頭の改行は削除されてしまう 179 current_data = "" 180 181 return blocks
指定文字数でテキストを行単位で分割してリストにする
Arguments:
- text (str): 対象文字列
- limit (int, optional): 分割文字数. Defaults to 2000.
Returns:
list[str]: 分割リスト