文字列を出力して行末に達したときは、改行して次の行の先頭から表示しなければなりません。
行末に達したかどうかは currentpoint で現在の位置を求め、 stringwidth で印刷しようとする文字列の幅を求めれば良いのですが、長い文章全体の幅を求めても意味がありません。文字列を1文字と残りの文字列に分けて、 その1文字の幅から改行すべきかどうか判定するようにします。
PostScriptでは1バイトで文字列から一部文字列を取得できますが、EUC-JP の文字列は1バイト、2バイト、3バイト文字が入り乱れています。
1バイト、2バイト、3バイト文字と長さを考慮しながら、先頭の1文字と残りの文字列に分割する手続きを作成します。
%!PS-Adobe-3.0 /mm { 2.834645669 mul } def newpath /Space 3 mm def /Left 20 mm def /Ryumin-Light-EUC-H findfont 20 scalefont setfont /vPosition 297 mm 20 mm sub def % A4 297mm /hPosition Left Space add def /newline { /vPosition vPosition 25 sub def hPosition vPosition moveto } def hPosition vPosition moveto (Hello,world!) 0 get == %=> 72 (あ) 0 get == %=> 164 (あ) 1 get == %=> 162 5 string == % (\000\000\000\000\000) /str 5 string def str 0 16#2a put %=> '*' str 1 16#30 put %=> '0' str 2 164 put str 3 162 put str show %=> "*0あ" が表示される。 % 半角カナは 8ea1 〜 8edf /s 5 string def s 0 16#8e put s 1 16#dc put %=> 'ワ' s 2 16#8e put s 3 16#dd put %=> 'ン' newline s show %=> "ワン" が表示される。 % newline (。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテト) show % newline (ナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚) show % 先頭から指定長の文字列を取得して返す。 /Head { 0 exch getinterval} def % 指定位置より後ろ文字列を返す。 % 参考:ローカル変数に値を渡す方法 % http://www.cs.kyoto-wu.ac.jp/~konami/documents/ps/psmemo.html#subsec6:5 /ldict 1 dict def /Tail { ldict begin /start exch def /str exch def /len str length start sub def str start len getinterval end } def (abcdefghijk) 2 Head == % (ab) (abcdefghijk) 2 Tail == % (cdefghijk)
位置を指定して文字列を分割できるようになりましたので、先頭が1バイト文字のときは1バイトと残り、2バイト文字のときは2バイトと残り、3バイト文字のときは3バイトと残りに分割するようにします。
% 数字から文字列へ 1.2345 20 string cvs == %=> (1.2345) (abcdefghijk) 0 get 16#7e le == (あabcdefghijk) 0 get 16#7e le == /isASCII { 16#7e le } def % 半角カナは 8ea1 〜 8edf /isHANKAKU { 16#8e eq } def % 1byte 文字 % 拡張漢字 3byte :8FA1A1 〜 8FE9F8(FEFE) /isKAKUCHO { 16#8F eq } def % 3byte 文字 % A1A1 〜 E9F8(FEFE) /isKANJI { dup 16#a1 ge exch 16#e9 le and} def (abcdefghijk) 0 get isASCII == % => true (アイウエオカキクケコサ) 0 get isASCII == % => false (あabcdefghi) 0 get isASCII == % => false (アイウエオカキクケコサ) 0 get isHANKAKU == % => true (abcdefghijk) 0 get isHANKAKU == (あabcdefghi) 0 get isHANKAKU == (あいう) 0 get isKANJI == % => true % 1バイト、2バイト、3バイト文字を考慮しながら、先頭の1文字と残りの文字列を分けて % スタックに積みます。 % 1バイト以上の文字列でないと str 0 get のときスタックアンダーフローになります。 /sdict 1 dict def /Split { sdict begin /str exch def str 0 get isASCII { str 1 Tail str 1 Head} % 1byte 文字 { str 0 get isKAKUCHO { str 3 Tail str 3 Head} % 3byte 文字 { str 2 Tail str 2 Head} ifelse } ifelse end } def (aあイウ漢いうえおcdefghijk) Split newline show % => a Split newline show % => あ Split newline show % => イ Split newline show % => ウ Split newline show % => 漢 newline show % => いうえおcdefghijk clear (あ) Split pstack % (\244\242) () clear showpage