const PAGEBREAK_PREFIXES = ["問題文 (日本", "章"];
const SCRIPT_NAME_MULTI_PREFIX = 'カスタム 改ページ (複数前方一致)';
const SCRIPT_ERROR_MENU_NAME_MULTI_PREFIX = `${SCRIPT_NAME_MULTI_PREFIX} (設定エラー)`;
function getValidPrefixes(prefixes) {
if (!Array.isArray(prefixes)) {
return [];
}
return prefixes.filter(prefix => typeof prefix === 'string' && prefix.trim().length > 0);
}
function onOpen_MultiPrefix() {
try {
const validPrefixes = getValidPrefixes(PAGEBREAK_PREFIXES);
if (validPrefixes.length === 0) {
Logger.log(`onOpen_MultiPrefix: 有効な改ページ接頭辞が設定されていません (${JSON.stringify(PAGEBREAK_PREFIXES)})。エラーメニューを表示します。`);
showConfigurationErrorMenu_MultiPrefix("有効な改ページ接頭辞が設定されていません");
return;
}
let menuItemText = `指定接頭辞 (${validPrefixes.slice(0, 2).map(p => `"${p}"`).join(', ')}...)の前で改ページ`;
if (validPrefixes.length === 1) {
menuItemText = `接頭辞 "${validPrefixes[0]}" の前で改ページ`;
} else if (validPrefixes.length === 2) {
menuItemText = `接頭辞 (${validPrefixes.map(p => `"${p}"`).join(', ')})の前で改ページ`;
}
DocumentApp.getUi()
.createMenu(SCRIPT_NAME_MULTI_PREFIX)
.addItem(menuItemText, 'insertPageBreakAtPrefixMarkers')
.addToUi();
Logger.log(`onOpen_MultiPrefix: メニューを正常に追加 (有効な対象接頭辞: ${JSON.stringify(validPrefixes)})。`);
} catch (e) {
Logger.log(`onOpen_MultiPrefix: メニュー追加中にエラー: ${e}\n${e.stack}`);
showConfigurationErrorMenu_MultiPrefix("メニュー追加中にエラー発生");
}
}
function showConfigurationErrorMenu_MultiPrefix(reason) {
try {
DocumentApp.getUi()
.createMenu(SCRIPT_ERROR_MENU_NAME_MULTI_PREFIX)
.addItem(`設定を確認 (${reason})`, 'showConfigurationError_MultiPrefix')
.addToUi();
} catch (e) {
Logger.log(`showConfigurationErrorMenu_MultiPrefix: エラーメニュー表示中にさらにエラー: ${e}`);
}
}
function showConfigurationError_MultiPrefix() {
let currentSetting = "未定義またはアクセス不能";
try {
currentSetting = typeof PAGEBREAK_PREFIXES !== 'undefined'
? (Array.isArray(PAGEBREAK_PREFIXES) ? JSON.stringify(PAGEBREAK_PREFIXES) : `無効な設定値 (${PAGEBREAK_PREFIXES})`)
: "未定義";
} catch(e) {
currentSetting = "設定値の表示中にエラーが発生しました";
}
const message = `スクリプトの設定に問題があります。\n\n`
+ `現在の設定値 (PAGEBREAK_PREFIXES): ${currentSetting}\n\n`
+ `スクリプトエディタを開き、ファイルの先頭にある「PAGEBREAK_PREFIXES」の値を確認・修正し、**ファイルを保存**してください。\n\n`
+ `この値は、改ページの目印となる**空でない**接頭辞文字列を **1 つ以上**含む**配列**(例: ["PREFIX1", "PREFIX2"])である必要があります。\n`
+ `空文字列 "" や空白のみ " " は無視されます。\n\n`
+ `(例: const PAGEBREAK_PREFIXES = ["Chapter ", "Section ", "図-"];)`
DocumentApp.getUi().alert("スクリプト設定エラー", message, DocumentApp.getUi().ButtonSet.OK);
}
function insertPageBreakAtPrefixMarkers() {
const startTime = new Date();
let doc;
try {
doc = DocumentApp.getActiveDocument();
if (!doc) throw new Error("アクティブなドキュメントを取得できませんでした。");
doc.getName();
} catch (e) {
handleExecutionError_MultiPrefix("ドキュメントアクセスエラー", e);
return;
}
const validPrefixes = getValidPrefixes(PAGEBREAK_PREFIXES);
if (validPrefixes.length === 0) {
Logger.log(`insertPageBreakAtPrefixMarkers: 処理開始前にチェックした結果、有効な改ページ接頭辞が設定されていません。`);
showConfigurationError_MultiPrefix("有効な改ページ接頭辞が設定されていません");
return;
}
Logger.log(`--- 複数前方一致による改ページ挿入処理 開始 ---`);
Logger.log(`ドキュメント: ${doc.getName()}`);
Logger.log(`有効な対象接頭辞 (実際に検索に使用): ${JSON.stringify(validPrefixes)}`);
const body = doc.getBody();
const numChildren = body.getNumChildren();
let pageBreakInsertedCount = 0;
let foundMarkersCount = 0;
Logger.log(`要素数: ${numChildren}。逆順に走査します...`);
for (let i = numChildren - 1; i >= 0; i--) {
const element = body.getChild(i);
if (element.getType() === DocumentApp.ElementType.PARAGRAPH) {
const paragraph = element.asParagraph();
let paragraphText;
try {
paragraphText = paragraph.getText();
if (validPrefixes.some(prefix => paragraphText.startsWith(prefix))) {
foundMarkersCount++;
if (i > 0 && body.getChild(i - 1).getType() !== DocumentApp.ElementType.PAGE_BREAK) {
try {
body.insertPageBreak(i);
pageBreakInsertedCount++;
} catch (insertError) {
Logger.log(`! Index ${i} への改ページ挿入中にエラー: ${insertError}`);
}
}
}
} catch (elementError) {
Logger.log(`! Index ${i} (Type: PARAGRAPH) の処理中にエラー: ${elementError}. スキップします。`);
}
}
}
const endTime = new Date();
const duration = (endTime.getTime() - startTime.getTime()) / 1000;
Logger.log(`--- 走査終了 ---`);
Logger.log(`処理時間: ${duration.toFixed(2)} 秒`);
Logger.log(`検出された指定接頭辞で始まる段落 (${JSON.stringify(validPrefixes)}): ${foundMarkersCount} 個`);
Logger.log(`挿入された改ページ: ${pageBreakInsertedCount} 個`);
const resultMessage = buildResultMessage_MultiPrefix(pageBreakInsertedCount, foundMarkersCount, validPrefixes, duration);
DocumentApp.getUi().alert("処理完了", resultMessage, DocumentApp.getUi().ButtonSet.OK);
Logger.log(`--- 複数前方一致による改ページ挿入処理 終了 ---`);
}
function handleExecutionError_MultiPrefix(context, error) {
Logger.log(`実行時エラー (${context}): ${error}\n${error.stack}`);
let userMessage = `スクリプトの実行中にエラーが発生しました。\n\n状況: ${context}`;
if (error.message) {
if (error.message.includes("Authorization required") || error.message.includes("権限が必要")) {
userMessage = "スクリプトの実行に必要な権限が承認されていません。\n\nドキュメントを再読み込みするか、スクリプトを再度実行し、承認画面で許可してください。";
} else {
userMessage += `\n詳細: ${error.message}`;
}
}
DocumentApp.getUi().alert("スクリプト エラー", userMessage, DocumentApp.getUi().ButtonSet.OK);
}
function buildResultMessage_MultiPrefix(insertedCount, foundCount, validPrefixes, duration) {
const displayPrefixes = validPrefixes.slice(0, 3).map(p => `"${p}"`);
const prefixDescription = `指定された接頭辞 (${displayPrefixes.join(', ')}${validPrefixes.length > 3 ? '...' : ''}) で始まる段落`;
if (insertedCount > 0) {
return `${insertedCount} 箇所の ${prefixDescription} の前に改ページを挿入しました。\n\n処理時間: ${duration.toFixed(2)} 秒`;
} else if (foundCount > 0) {
return `${prefixDescription} は ${foundCount} 箇所で見つかりましたが、改ページは挿入されませんでした。\n(段落が先頭にあるか、既に改ページが存在するため)\n\n処理時間: ${duration.toFixed(2)} 秒`;
} else {
return `${prefixDescription} が見つかりませんでした。\n\n以下の点を確認してください:\n`
+ `1. スクリプト上部の「PAGEBREAK_PREFIXES」に有効な接頭辞が設定されていますか? (現在の有効な設定: ${JSON.stringify(validPrefixes)})\n`
+ `2. ドキュメントに、これらの接頭辞のいずれかで始まる段落が存在しますか? (大文字/小文字も区別)\n`
+ `3. スクリプトの権限は承認されていますか?`;
}
}