索引の見出しで使用するページ番号のみ太字に

[7148]索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/10/31 15:16:39
Windows XP, InDesign CS5です。

用語索引のある本を制作しています。今回、索引のページ番号をその単語が見出しの中にある場合のみ太字にしてほしいという要望があり、どのように作業をすすめようか悩んでいます。索引は、外部テキストから索引を作るJavascriptを使用して作っています。

現在考えている手順は
1. 今まで通りの索引を作る(これで抽出したページ番号をAとします)
2. 同じ索引項目を使用して見出しのみから索引を作る(スクリプトで検索オプションに見出しの段落スタイルを指定)(同じくBとします)
3. AとBを比較して、AのうちBにマッチする数字のみ太字にする。(タブ区切りテキストで書き出してExcelで 条件付き書式を設定)

これで可能かとは思いますが、どうにもスマートとは言いがたい(特に手順3)ので、使えそうなアイデアがありましたら教えていただけると助かります。
よろしくお願いします。
[7149]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:ginsburg 投稿日:2012/10/31 19:35:22
私もちょうど特殊な索引作成に取り組んでいて、プログラミングのスキルは未熟なのですが気がついた点を少しお伝えします。

>(タブ区切りテキストで書き出してExcelで 条件付き書式を設定)
「条件付き書式」をExcelでつけるとのこと。
ただ最終的にはInDesignに流すと思いますが、その場合スタイルの反映はどのようになさる計画でしょうか?

私が進めるとしたら、どうプログラムするかは別として、
以下のように考えます。
1.今まで通りの索引を作る(ご提示の索引リストA)
2.「見出しの段落スタイル」を割り当ててある同じ索引項目を探し、そのノンブル一覧を書き出す(ご提示のAから該当しない要素を削除したデータ)
3.1.で作った索引データを調べ、2.のノンブル一覧に合致する行に太字の段落スタイルを割り当てる

こう思いつきましたが如何でしょうか?
アイデアしかお出しできませんが、ご了承ください。
[7150]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:ginsburg 投稿日:2012/10/31 22:29:39
すみません、後から思いつきました。

先に書いた1.と2.はまとめられそうですね。

「索引項目を見つけた箇所のノンブルと段落スタイルの名前を調べて書き出す」

「書き出した情報をもとに、段落スタイルの名前が『見出し』だったらその索引項目を太字にする」
これでいかがでしょうか。
[7152]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/02 10:41:00
ginsburgさん
レスありがとうございます。

検索項目の単語や行全体ではなく、特定のページ数のみを太字にしたいという要望なのです。
例えば、hogehogeという単語がファイル中にあるとします。
普通に索引を作ると

(リストA)hogehoge 1, 5, 15, 20

となりますが、hogehogeはP5とP20で見出しに使用されています。

(リストB)hogehoge 5, 20

この2つのデータを比較して、リストAの5と20だけを太字にするという処理をしたいということです。

>エクセルからのスタイルの反映
エクセルデータ上で該当ページ数に条件付き書式で色をつける等の処理をしておいてInDesignにペーストし、「表をテキストに変換」でテキストデータに戻し、文字色を検索して太字に置換するという手順です。

エクセルより正規表現置換で解決でききそうな気がしてきました。

リストBを
myWord = hogehoge, myNum = 5
myWord = hogehoge, myNum = 20
として
(?<=myWord.+ )myNum(?=,|\r)
で置換…できませんでした。どうも正規表現の記述がおかしいようです。
[7153]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:ginsburg 投稿日:2012/11/02 11:00:49
改めてお話を伺って、結果が見えてきました。

気が付いた点を一つだけ。

>リストBを
>myWord = hogehoge, myNum = 5
>myWord = hogehoge, myNum = 20
>として
>(?<=myWord.+ )myNum(?=,|\r)
>で置換…できませんでした。

これは変数が文字列じゃないからだと思います。
正規表現は数値変数には使えないので、文字列に変換する必要があります。
該当するノンブル文字列に、文字スタイルのタグを付けるとよいかもしれません。
[7154]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/02 12:19:35
正規表現置換はまとめて処理できるようにjavascript化するつもりなので、おかしな書き方をしてしまいました。

リストAに対し
検索:(?<=hogehoge.+ )5(?=,|\r)
または(?<=hogehoge.+ )20(?=,|\r)
置換:$1(置換形式に太字の文字スタイルを指定)
という正規表現置換をかけましたが、どちらもヒットしなかったということです。

調べてみたら、InDesignの正規表現では後読みに+は使えないんですね。うーん。
[7156]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:杜王町民 投稿日:2012/11/02 17:29:24
もし1行ごとに作業するという手順でもかまわないならば、

検索:(?<=\, )(5|20)(?=\, |\r)
置換:$1
で「5」と「20」を同時に太字へ置換できます。
ただ、これはあくまでInDesignの検索設定における正規表現です。
Excelの単語が入っている列の内容をInDesign上で調べ、該当する行が見つかったら太字にしたい数値を正規表現で置換する…という方法は如何でしょうか。
ただ、ご計画の「各行の単語を含めて検索する」ことができればもっと効率が良いのは間違いありませんが、表現法を思いつきませんでした。
[7160]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:オメガ 投稿日:2012/11/03 13:57:25
非常に興味深く、勉強になります。
杜王町民さんの示された処理をスクリプトで自動化すればできそうな気がします。
リストB(タブ区切りテキスト)を読み込み配列に入れる→各項目の文字列でリストA内を検索→見つかったテキストのある段落で正規表現検索置換 という手順でいかがでしょう。
[7163]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/05 14:32:19
単語とページを両方含めて正規表現検索する方法を模索していて、リストBだけでなくリストAも加工して処理することを思いつきました。
リストAのページ数が1つだけならリストBを正規表現で表現できます。いったんリストAを項目とページ数を1つずつのペアにばらし、せうぞーさんの「regex_continuous_substitution.jsx」で一気に文字スタイルをかけ、再度まとめ直すという手順です。
http://d.hatena.ne.jp/seuzo/20080601/1212331508

1. (リストB)hogehoge 5, 20 を正規表現置換で置換テーブル用テキストに変換します。
(?<=hogehoge )(5|20)(?=\, |\r) $1 c:見出し内

2. (リストA)hogehoge 1, 5, 15, 20 を正規表現置換でばらします。
hogehoge 1
hogehoge 5
hogehoge 15
hogehoge 20

3. ばらしたリストAに「regex_continuous_substitution.jsx」を置換テーブル用テキストとしてリストBを指定して実行します。

4. 最後にばらしたリストA元通りに正規表現置換でまとめ直します。

リストAをばらす&まとめる処理については、kinさんの「InDesignで索引を作る3」からヒントをいただきました。
http://ameblo.jp/knym71/entry-10778772241.html#main
正規表現などの詳しい手順は後日まとめます。

実際のデータでテストしていますが、太字変換に関しては問題なし、ばらしとまとめに漏れが出そうなのがやや難点です。
杜王町民さんとオメガさんの案のスクリプトについても引き続き検討しています。
[7167]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:杜王町民 投稿日:2012/11/06 01:13:18
2.~4.の処理のどの段階でノンブルを太字にできるかちょっとつかみかねているのですが、3.のリストBを置換テーブルにするところで太字になるのでしょうか?
[7168]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/06 11:17:36
そうです。regex_continuous_substitution.jsxの正規表現での連続検索置換は置換時にスタイルを指定できますので、それを利用しています。
この場合、「見出し内」という名前の文字スタイルを置換形式に指定しているので、置換テーブルの最後が「c:見出し内」となっています。
[7173]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:杜王町民 投稿日:2012/11/07 01:12:24
「リストA」の内容を「ばらす」スクリプトを作ってみました。
Mac版CS5、置き換える内容のチェックやエラーチェックの処理は入っていません。
あくまでデータ上のテキストが、
abcd 00, 22, 33, 55, 111
というように「単語:半角スペース:1バイト数字:カンマ:半角スペース…1バイト数字:改行」
ときちんと入力されていることが条件です。


もしお気に召しましたらお使いください。

//選択したテキストフレーム内の単語:ノンブルを1行ずつに分解する
//フレーム内でカーソルを立てて実行した場合はその段落のみ処理

var sel = app.activeDocument.selection[0];
alert(sel.paragraphs.length);
for(i=0;i<sel.paragraphs.length;i++){
//各段落の内容を代入
var selStr =sel.paragraphs[i].contents;
//スペースで段落の内容を分割し、単語とノンブルに分ける
separates = selStr.split(" ");
//配列の最初の内容は単語として別変数に代入
word=separates[0];
//数字の最後の1文字を取って単語と連結し、新しい段落内容を作る
for(j=1; j<separates.length;j++){
separates[j]=word+" "+separates[j].slice(0,-1)+"\r";
}
//各段落をつなげて流し込むテキストを作成する
content="";
for(var k=1;k<separates.length;k++){
content +=separates[k];
}
//既存の段落の内容を差し替える
sel.paragraphs[i].contents=content;
}
[7174]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/07 14:41:01
杜王町民さん、ありがとうございます。
正規表現置換を複数回かける方法ですと、ページ数が20ある場合「もどし」は5回の置換ですみますが、「ばらし」は20回置換する必要があったので、スクリプト化できると大変ありがたいです。

//数字の最後の1文字を取って単語と連結し、新しい段落内容を作る
for(j=1; j<separates.length;j++){
separates[j]=word+" "+separates[j].slice(0,-1)+"\r";
}
この処理がよく分かりません。
文字列がabcd 00, 22, 33, 55, 111の場合、abcd 00, 22, 33, 55, 11(改行)が得られますよね。
この処理を繰り返して、数字部分のカンマやスペースがなくなり数字は2桁以上でも残るのはどうしてでしょうか?
[7175]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:杜王町民 投稿日:2012/11/07 17:46:18
>文字列がabcd 00, 22, 33, 55, 111の場合、abcd 00, 22, 33, 55, 11(改行)が得られますよね。
>この処理を繰り返して、数字部分のカンマやスペースがなくなり数字は2桁以上でも残るのはどうしてでしょうか?

お尋ねのこの件についてお答えします。

このスクリプトの最初のキモはこのひとつ手前です。

//スペースで段落の内容を分割し、単語とノンブルに分ける
separates = selStr.split(" ");

プログラムで扱うものに「配列」というのがあります。
配列そのものについてはさまざまな資料をあたっていただければと思います。
ここで、1行の文字列を1バイトスペース区切りで「ばらす」処理をしています。
selStrに「abcd 00, 22, 33, 55, 111(改行)」が入っていた場合、結果は以下のようになります。
separates[0]="abcd"
separates[1]="00,"
separates[2]="22,"
separates[3]="33,"
separates[4]="55,"
separates[5]="111(+改行1文字)"
ここで概ね分解はできていますが、0番目の単語以外はカンマや改行文字が邪魔ですね。
また、0番目を本文に流してしまうと、ノンブルのない単語だけの行が増えてしまいます。
そこで、本文として流す内容は
単語+1バイトスペース+「1~5番目の要素から最後の1文字を取った内容」+改行
にすればよいということが判断できます。

>for(j=1; j<separates.length;j++){
は、配列にしたseparatesの1番目から配列の長さ全体-1番目までを繰り返し処理するループです。
「separates.length」とすると、分割された配列の「長さ/数」がわかり、0~5までの「6個」という結果になるのですが、「6」番目の要素はないので、5までに留める処理を「j<separates.length」という形でしています。
ちなみに6番目まで含める場合は
「j<=separates.length」
と、「=」をつけます。

>separates[j]=word+" "+separates[j].slice(0,-1)+"\r";
ここで、ばらした後の1行全体を一度で組み立てます。
separates[j].slice(0,-1)というのはJavaScriptの機能で、
「sliceの直前で指定した文字列separates[j]の0番目から全体よりー1文字少ない長さの文字を抜き出す」
という動作をします。
separates[j]の内容が"00,"ですと、
0番目…0
1番目…0
2番目…,
ですので、0番目から2"-1"の「1番目」までを抜き出します。
その前に単語が入っている文字列の変数「word」と1バイト巣スペース、一番最後(ノンブルの後)には改行文字を付け加え、この全体を改めてseparates[j]に代入しなおします。
なお、"111改行"であれば、
0番目…1
1番目…1
2番目…1
3番目…改行文字
となります。
最終的には「111」だけになります。
取り出す文字の長さはバラバラですから、ノンブルそのものが1桁でも3桁でも対応できるわけです。
[7176]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/07 18:37:00
とても丁寧な説明ありがとうございます。
あーなるほど!

>あくまでデータ上のテキストが、
>abcd 00, 22, 33, 55, 111
>というように「単語:半角スペース:1バイト数字:カンマ:半角スペース…1バイト数字:改行」
>ときちんと入力されていることが条件です。

というのはこのためなんですね。勉強になりましたm(_ _)m
[7177]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:杜王町民 投稿日:2012/11/07 20:57:17
追伸です。

>正規表現置換を複数回かける方法ですと、ページ数が20ある
>場合「もどし」は5回の置換ですみますが、「ばらし」は20回
>置換する必要があったので、スクリプト化できると
>大変ありがたいです。

こちらの件ですが、複数ページに流してあっても連結で1つの
ストーリーになっていれば、おそらくテキストを全選択する
ことで一度起動すれば全部の行をばらしてくれると思います
(実データがないので確証が持てず申し訳ありません)。
[7182]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:オメガ 投稿日:2012/11/09 08:03:40
>Subiさん
テキストをばらすというのは思い付きませんでした。何より既存のスクリプトと検索置換で処理できる点が良いですね。

>杜王町民さん
テキストを用意して試してみましたが、全選択では途中で参照エラーが起きました。先頭の段落から処理しているのが原因かと。
また蛇足ですが、slice(0,-1)は、separates[j]=word+" "+separates[j].replace(",","\r"); としてカンマを改行に置換すればいいのではないでしょうか。slice()はあまり使った事がなかったので勉強になりました。



さて、以前挙げたスクリプトも書いてみました(簡易版です)。一応動くと思いますが。
こちらは索引項目とページ数の間はタブ区切り、カンマの後は半角スペースを前提にしています。
※リストBを読み込んで配列に入れるの処理は省略しています。myList配列がリストBに該当します。
※リストAのストーリー全体を処理します。見つかったテキストの文字色をシアンに変えます。添付の図のようになります。
※リストA内にカーソルを置くか、テキストフレームを1つ選んで実行して下さい。

var myDoc=app.documents[0];
var myStory=myDoc.selection[0].parentStory; //リストAのストーリー
var myList=[ //リストBの内容
["hogehoge","5, 20"],
["fugafuga","6, 21"]
];
//検索置換の環境設定
app.findGrep.Preferences=NothingEnum.NOTHING;
app.changeGrepPreferences=NothingEnum.NOTHING;
app.findChangeGrepOptions.includeLockedLayersForFind=false;
app.findChangeGrepOptions.includeLockedStoriesForFind=false;
app.findChangeGrepOptions.includeHiddenLayers=false;
app.findChangeGrepOptions.includeMasterPages=false;
app.findChangeGrepOptions.includeFootnotes=false;
app.findChangeGrepOptions.kanaSensitive=true; //かなを区別
app.findChangeGrepOptions.widthSensitive=true; //大文字小文字を区別
//以下メイン処理
for(var i=0; i<myList.length; i++){
app.findGrepPreferences.findWhat="^"+myList[i][0]+"\\t";
var myMatchWords=myStory.findGrep(); //項目名で検索
if(myMatchWords.length>0){
for(var j=0; j<myMatchWords.length; j++){
var targetPara=myMatchWords[j].paragraphs[0]; //見つかったテキストを含む段落
app.findGrepPreferences.findWhat="(?<=, |\\t)("+myList[i][1].replace(/, /g,"|")+")(?=, |\\r|\\>)";
app.changeGrepPreferences.fillColor=myDoc.colors.item("Cyan");
targetPara.changeGrep(); //正規表現で置換
}
}
}
app.findGrepPreferences=NothingEnum.NOTHING;
app.changeGrepPreferences=NothingEnum.NOTHING;

attached image
[7183]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/09 12:15:10
>杜王町民さん、オメガさん
お二人ともありがとうございます!大変勉強になります。

テストでは問題なく動作しているようでしたが、本データでテストをはじめると問題点があることがわかってきました…

杜王町民さんのスクリプトですが、リストAの本データには索引の英単語2語以上のものがありました。
(リストAの例)piyo piyo 10, 100
つまり索引単語中に半角スペースが含まれるので、半角スペースで分ける方法はとれないということです。
日本語の索引なら問題ないのですが…私の提示条件不足でした。

オメガさんのスクリプトは、リストAの先頭のページ数はシアンに変換されませんでした。
(リストBの例)["hogehoge","1"]
ページ数の前にタブがある場合を想定していないのかと思いましたが、正規表現置換の後読みで指定されているので原因がつかめないでいます。
[7186]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:杜王町民 投稿日:2012/11/09 21:44:56
オメガさん

>テキストを用意して試してみましたが、全選択では途中で参照エラーが起きました。先頭の段落から処理しているのが原因かと。

動作チェックありがとうございました。
私は2段落分しか用意しなかったためか、おっしゃる「参照エラー」が出ませんでしたが、もう少し長いデータを用意して試してみたいと思います。

>また蛇足ですが、slice(0,-1)は、separates[j]=word+" "+separates[j].replace(",","\r"); としてカンマを改行に置換すればいいのではないでしょうか。slice()はあまり使った事がなかったので勉強になりました。

実は正規表現で置換する方法が思い浮かばなかったための苦肉の手段でした。

Subiさん
>杜王町民さんのスクリプトですが、リストAの本データには索引の英単語2語以上のものがありました。
(リストAの例)piyo piyo 10, 100
つまり索引単語中に半角スペースが含まれるので、半角スペースで分ける方法はとれないということです。

実は最初にスクリプトを作っていて、「見出しが2ワード以上の項目だとスペースが入るからまずいか?」とふと思ったりもしたのですが、そのまま作ってしまいました。
やはり、オメガさんご考案のとおりに単語とノンブル一覧はタブで区切ったほうがよさそうな気がします。
ただ、現状のデータでは単語の区切りもノンブルとの境目も全てスペースなんですよね。
別の処理法を考えなければならなそうです。
[7187]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:オメガ 投稿日:2012/11/09 22:33:57
検証不足でした。すみません。

24行目の、
app.findGrepPreferences.findWhat="(?<=, |\\t)("+myList[i][1].replace(/, /g,"|")+")(?=, |\\r|\\>)";
で、正規表現検索の文字列を指定しているのですが、この指定がおかしいようです。
(?<=, |\t)(5|20)(?=, |\t|\>)としているのですが、肯定後読みのタブが無視されるようですね。

どこかで見たような…と思ったら、せうぞーさんが以前記事にされていました。ありがとうございます。
http://d.hatena.ne.jp/seuzo/20110402#20110402f2

また肯定先読みの方は単語の終わり(\>)を入れると、カンマも改行も意味がないことに気付きました。これは最終段落に改行が抜けていた場合を想定して入れています。

以上をふまえて24行目を、
app.findGrepPreferences.findWhat="(?<=, )("+myList[i][1].replace(/, /g,"|")+")(?=\\>)"+"|"+"(?<=\\t)("+myList[i][1].replace(/, /g,"|")+")(?=\\>)";
としてはいかがでしょうか。
それでも索引項目に同様の書式がある可能性はゼロではないので注意が必要ですね。

他にも問題点等ありましたらご指摘いただけると幸いです。
[7188]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:杜王町民 投稿日:2012/11/10 01:14:06
まだ完全に動作していないのですが、単語と最初のページ番号の区切りをスペースからタブに置き換える処理を考えました。

//キーワードとノンブルに挟まれたスペースをタブに置き換える
selStr=selStr.replace(/([a-zA-Z]+?)\s([0-9]+?)/,"$1\t$2");

これならば、行頭からみて最後の英単語と最初に見つかる数字との間のスペースだけをタブに変換できます。
[7189]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/10 13:51:40
>オメガさん
確認しました。問題ないです!ありがとうございます。m(_ _)m
正規表現内でreplaceを使う方法には驚きました。こんな書き方できるんですね。

>杜王町民さん
項目にスペースや数字が含まれる可能性がありますので、この際最初のリストA・リストBのデータの時点で項目とページ数の区切りはタブであるという前提にしたいと思います。いろいろ考えてくださったのに申し訳ありません。
しかし、スペース区切りで作成した既存の索引に、改訂とともに太字処理を…ということになることも十分考えられますので、アイデアはとても参考にしております。

しかし、リストAとリストBがタブ区切りであるという前提で手順を再確認していたところ、正規表現検索置換で置換文字列に「\t」を入れると置換結果がタブになってしまい頭を抱えています。「\\t」ですと\とタブになり、16進文字列で「\x{005C}\x{0074}」としてもやはりタブになってしまいます。特に区切り文字としてタブにこだわるわけではないので、確実に項目に出てこない空白文字(emスペースなど)を使ったほうが楽な気がしてきました…
[7190]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:杜王町民 投稿日:2012/11/10 14:08:23
確かにキーワードが数字を含むというケースもあり得ますね。

さて区切り文字の件ですが、見てわかりやすい"|"はいかがでしょうか。
[7191]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:オメガ 投稿日:2012/11/10 14:09:58
>杜王町民さん
項目が必ずしも英単語のみとも言い切れないですし、
InDesign CS 5 11, 12, 13
ならCSの後にタブが入ってしまいます...

他にも方法はあると思いますが、たとえば
1.カンマ+スペース(, )をカンマ2つ(,,)に置き換えます。
2.最初のページ番号から行末までは数字とカンマのみ(と改行)になるので、行末から最初に出てくるスペースを正規表現でタブに置き換えます。
検索:\s(?=[0-9,]+\r) 置換:\t
3.カンマ2つを元に戻します。
という手順でほぼ確実に置き換えられると思います。

あー、正規表現でもいけそうですね。
ページ番号が
・1つしかない場合 XXXX \d+\r
・2つ以上ある場合 XXXX (\d+, )+\d+\r
 ページ番号間のスペースの前は必ずカンマ→項目名の末尾はカンマではない とすると
(?<!,)\s(?=(\d+, )*\d+\r)
をタブに置き換えればいいのではないでしょうか。
[7192]Re: 索引の見出しで使用するページ番号のみ太字に 投稿者:Subi 投稿日:2012/11/10 14:46:44
>杜王町民 さん
検索置換しやすい文字ならなんでもいいです^^
私はできるだけ正規表現検索置換で処理するアプローチなので勝手に困ってるだけです(笑)

>オメガさん
それいただきました!
最終行に改行がない場合を考えて
(?<!,)\s(?=(\d+, )*\d+$)
にすればもっとよさそう。
この記事の書き込み元へのリンク (コメントや質問などはこちらへどうぞ)