Coverage for graphica/core/caption_export.py: 100.0%
18 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
1"""論文用の LaTeX のコードとキャプションを作る。GUI には依存しない。"""
2import re
4# 1文字ずつ1回だけ置き換える(順に replace すると、置き換えで生まれた \ まで二重にエスケープしてしまう)
5_LATEX_SPECIAL_CHARS = {
6 '\\': r'\textbackslash{}',
7 '{': r'\{',
8 '}': r'\}',
9 '$': r'\$',
10 '&': r'\&',
11 '%': r'\%',
12 '#': r'\#',
13 '_': r'\_',
14 '~': r'\textasciitilde{}',
15 '^': r'\textasciicircum{}',
16}
18DEFAULT_WIDTH = r'\linewidth'
21def escape_latex(text: str) -> str:
22 if not text:
23 return ''
24 return ''.join(_LATEX_SPECIAL_CHARS.get(ch, ch) for ch in text)
27def sanitize_label(text: str, prefix: str = 'fig:') -> str:
28 """タイトルなどから \\label{} に使える文字列を作る(英数字・-・_ だけ残す)。何も残らなければ既定の名前。"""
29 cleaned = re.sub(r'[^A-Za-z0-9_-]+', '', (text or '').strip().replace(' ', '-'))
30 # 日本語だけのタイトルなどで、ハイフンだけの意味の無いラベルにならないように
31 if not re.search(r'[A-Za-z0-9]', cleaned):
32 return f"{prefix}plot"
33 return f"{prefix}{cleaned}"
36def generate_latex_figure(image_filename: str, caption: str, label: str, width: str = DEFAULT_WIDTH) -> str:
37 """figure 環境一式。image_filename が空なら 'figure.pdf'(後で差し替える前提)、label が空なら \\label 行を省く。"""
38 lines = [
39 r'\begin{figure}[htbp]',
40 r' \centering',
41 f" \\includegraphics[width={width}]{{{image_filename or 'figure.pdf'}}}",
42 f" \\caption{{{escape_latex(caption)}}}",
43 ]
44 if label:
45 lines.append(f" \\label{{{label}}}")
46 lines.append(r'\end{figure}')
47 return '\n'.join(lines)