はじめに
第1回で示した完成図です。宛名書きを途中に挟んで縦の均等割付けなどは説明していますが、まだ説明していないもの、足りないものを補足します。
まず、これまでで説明していないのは追い出し禁則です。
また、縦の均等割付けを本格的に使用しています。前回の宛名の名前の部分ですでに使用していますが、枠の中に入れて初めて中心線合わせのありがたさが分かります。
今回は「教科」の欄が追加されています。この欄が必要かどうかは各学校の考え方次第ですが、追加する場合は使える行数が学年や選択によって変化するので面倒です。調査書の作成場面では必要なので、加えておきました。
科目名は決め打ちではなく、生徒ごとに履修している科目のみを表示するようになっています。そのために教科ごとの行数が変化します。
生徒名、校長名、担任名では姓名の間に半角スペースを置き、半角スベースの後には挿入するスペースを省くという特殊な均等割付けをしています。生徒名では外国語のカタカナ表記の場合もあります。ミドルネームを持つ場合もあるので姓+名の名前管理も対応を考えなければならなくなる可能性があります。
禁則処理
最初に追い出し禁則を説明します。句読点が行頭に来るときにはその前の一文字も一緒に次の行に持っていくというものです。
/** コンストラクタの直後に呼び出し、 必要があれば引数の kindic にある文字が次の行頭に来るとき、追い出し処理をする nextjbgn(旧版の変数) -> nxtcpibgn(新版の変数) -> nxtbgncpi */ public boolean setOidashiIfNeeded(String kindic){ if (!hasNext()) return false; //① if (5>str.codePointCount(0, str.length())) return false; //② int newidxbgn = zstr.offsetByCodePoints(0,nxtbgncpi); //③ String nexttop = zstr.substring(newidxbgn,zstr.offsetByCodePoints(0,nxtbgncpi+1)); if ( 0>kindic.indexOf(nexttop) ) return false; //④ int newlengthincp = str.codePointCount(0,str.length())-1; //⑤ int newlengthinindex = str.offsetByCodePoints(0, newlengthincp); //⑥ str = str.substring(0, newlengthinindex); //⑦ nxtbgncpi--; //⑧ remm = wdmm - fm.stringWidth(str)*pt2mm; //⑨ gapmm = remm/(newlengthincp-1); return true; //⑩ }
このメソッドは、AdjustString.javaのコンストラクタでインスタンスが作られた直後に呼び出します。コンストラクタは元の文字列(zstr)と書き始める(コードポイント数で表した)位置と印字幅を指定して呼び出されます。インスタンスには印字幅に書く事ができるける分の文字列がstrに格納され、strに入らなかった文字の先頭位置がnxtbgncpiに保持されます。追い出し禁則が必要なら、このstrを1つ減らし、nxtbgncpiも1つ前にずらせばいいのです。strについてはサロゲートペアを考慮しなければならないのでそこが分かりにくくなります。後に図解を試みます。
追い出し禁則プログラムの説明
プログラム解説をしておきます。丸付き数字はプログラム中の部分を指します。
zstr は行に分けられる前の文字列。
str はコンストラクタで切り取られた次に出力する文字列。
nxtbgncpi はstrの次にくる文字のコードポイント数で数えた位置(先頭は0)。
要するに普通に文字を数えたものです。サロゲートペアが含まれなければStringのlengthと一致します。
kindic は行頭に来ては困る文字からなる文字列。"、。,."など。
① そもそも次の行がない時は必要ありません。
② 並べる文字が少ない時は追い出し後の均等割付が不自然ですから何ももせず戻ります。
この例では5文字より少ない場合としています。この場合普通行で4文字、追い出した行は3文字になります。
③ ここからの2行で次の行の先頭文字を求めています。nexttopに格納します。
④ nexttopが引数の文字列(禁則文字からなる)であるkindicの中になければ何もせず戻ります。
⑤ ここに来たことは禁則文字になっていたということなので、strのコードポイント数を求めて1つ減じて新コードポイント数とします。
⑥ 新しいコードポイント数に相当する文字列の新インデクス数(lengthで求められる数)を求めます
⑦ 新インデクス数を使ってstrの文字列を減らします。
⑧ コードポイントで表したこの行を書き終わった時の次の文字の一を1つ減じます。
⑨ 指定幅との差(余り)を新しい文字列で計算し、文字数-1で割って均等割付時の文字間の長さを求めておきます。
⑩ trueは禁則の処理をしたという印です。
追い出し禁則を図解する
まず、サロゲートペアがまったくない時は簡単です。例えばこんな感じ。
zstr="行頭に句読点が来る場合には、1つ前の文字から次の行にする。";
一行に13文字入るとします。
サロゲートペアがなければ、③の時点で13文字入っているstrの長さは0から12の13です。nxtbgncpiの値は13で文字列のindexでも13です。
indexの13番目の文字は"、"なので、strの文字を1つ減じて12とし、nxtbgncpiも12とします。
サロゲートペアがなければ、文字の数と文字列.lengthは一致します。サロゲートペアがあれば、文字列.lengthの方が大きくなります。「文字の数」と「文字列の長さ」を区別しましょう。
サロゲートペアを考慮しなければならない例が普通の文章で出てくるのは稀なのですが、むりやり一番違いが出そうなstrの末尾の文字"は"を、サロゲートペアで表現される"ホッケ"の文字に入れ替えてみましょう。ホッケの文字は魚偏に花ですが、この連載の管理システムではうまく表現されないので"糀"で代用します。"糀"を見たら魚偏であると思ってください。
文章としては意味が通じませんが、文字列とすれば次のようになります。
zstr="行頭に句読点が来る場合に糀、1つ前の文字から次の行にする。";
やはり一行に13文字入るとします。
魚偏の"糀"はサロゲートペアで扱われるので、③の時点で13文字入っているstrの長さは0から13の14です。nxtbgncpiの値は13ですが、文字列のindexは14です。
indexの14番目の文字が"、"なので、strから文字を1つ減じますが、その文字がサロゲート文字なのでstrの長さとしては2を減らさなければなりません。nxtbgncpiの方は文字の数ですから12とします。