ベスト文集制作記録⑥(本文の組み方③・ベタ組篇)

本文の組み方③・ベタ組篇

小説の本文は、ベタ組にするのがよい。ベタ組とは、方眼紙に字を埋めるがごとく、字間を空けずに組むことである。次の画像のように組むということである。

hanmen.styの使用

LaTeXの標準機能でベタ組を実現するのは案外難しい。そこで、hanmen.styを使用する。これを用いると、ベタ組を実現しやすい。

ベタ組のための基本設定

次の設定をしておくと字間や行間が広がりにくく、ベタ組を実現しやすい。

%% 字間・行間の設定
\kanjiskip=0zw plus .25zw minus .03125zw
\xkanjiskip=.25zw plus .25zw minus .0625zw
\parskip=0zw
\parsep=0zw
\partopsep=0zw

縦中横

LaTeXで縦書きをする際、縦中横には\rensujiを使うよう言われる。しかし\rensujiだと無駄に\xkanjiskipが挿入されてしまい、ベタ組にならない。そこで\tcy命令を新たに作り、これを使うのがよい。

\usepackage{pxghost}

%% \tcy
\newcommand{\tcy}[1]{%
    \jghostguarded{%
        \leavevmode\hbox to 1zw{%
            \centering\rensuji*{#1}%
        }%
    }%
}

数字やアルファベットを自動で縦中横にするために、『九大文学』製作時にはPythonで次の関数を作って置換した。

nums = [
    ['0','0'],['1','1'],['2','2'],['3','3'],['4','4'],
    ['5','5'],['6','6'],['7','7'],['8','8'],['9','9']
]
alphabets = [
    ['A','A'],['B','B'],['C','C'],['D','D'],['E','E'],
    ['F','F'],['G','G'],['H','H'],['I','I'],['J','J'],
    ['K','K'],['L','L'],['M','M'],['N','N'],['O','O'],
    ['P','P'],['Q','Q'],['R','R'],['S','S'],['T','T'],
    ['U','U'],['V','V'],['W','W'],['X','X'],['Y','Y'],
    ['Z','Z'],
    ['a','a'],['b','b'],['c','c'],['d','d'],['e','e'],
    ['f','f'],['g','g'],['h','h'],['i','i'],['j','j'],
    ['k','k'],['l','l'],['m','m'],['n','n'],['o','o'],
    ['p','p'],['q','q'],['r','r'],['s','s'],['t','t'],
    ['u','u'],['v','v'],['w','w'],['x','x'],['y','y'],
    ['z','z']
]
def alphabet_replace(s):
    for x in alphabets:
        s = s.replace(x[0],'\\tcy{'+x[1]+'}')
    return s
def num_replace(s):
    for x in nums:
        s = s.replace(x[0],'\\tcy{'+x[1]+'}')
    return s
def percent_replace(x):
    x = x.replace('%', '\\tcy{\\%}')
    return x

禁則処理の抑制

禁則処理が多いとベタ組になりにくい。そこで禁則処理を程々に抑制する。縦書きの場合、禁則処理をこのように抑制したほうが商業誌の組み方に近づけられもする。

%% penalties
\clubpenalty=0
\widowpenalty=0
\jcharwidowpenalty=0
\displaywidowpenalty=0
\prebreakpenalty\jis"2147=10000  % 5000 ’
\postbreakpenalty\jis"2148=10000 % 5000 “
\prebreakpenalty\jis"2149=10000  % 5000 ”
\inhibitxspcode`〒=2
\prebreakpenalty\jis"2133=10000
\prebreakpenalty\jis"2134=10000
\prebreakpenalty\jis"2135=10000
\prebreakpenalty\jis"2136=10000
\prebreakpenalty`ー=0
\prebreakpenalty`ぁ=0
\prebreakpenalty`ぃ=0
\prebreakpenalty`ぅ=0
\prebreakpenalty`ぇ=0
\prebreakpenalty`ぉ=0
\prebreakpenalty`っ=0
\prebreakpenalty`ゃ=0
\prebreakpenalty`ゅ=0
\prebreakpenalty`ょ=0
\prebreakpenalty\jis"246E=0     %ゎ
\prebreakpenalty`ァ=0
\prebreakpenalty`ィ=0
\prebreakpenalty`ゥ=0
\prebreakpenalty`ェ=0
\prebreakpenalty`ォ=0
\prebreakpenalty`ッ=0
\prebreakpenalty`ャ=0
\prebreakpenalty`ュ=0
\prebreakpenalty`ョ=0
\prebreakpenalty\jis"256E=0     %ヮ
\prebreakpenalty\jis"2575=0     %ヵ
\prebreakpenalty\jis"2576=0     %ヶ
\prebreakpenalty\jis"2139=0     %々
\prebreakpenalty\jis"2144=0     %…

後になって思ったことだが、「々」の禁則処理はもう少し厳し目にしたほうがよかったかもしれない。また、禁則処理の抑制は\@tforを用いるともっと簡潔に記述できるようだ。

\clubpenalty=0
\widowpenalty=0
\jcharwidowpenalty=0
\displaywidowpenalty=0
\prebreakpenalty\jis"2147=10000 % 5000 ’
\postbreakpenalty\jis"2148=10000 % 5000 “
\prebreakpenalty\jis"2149=10000 % 5000 ”
\inhibitxspcode`〒=2
\@tfor\@i:=ヽヾゝゞ々〻\do{\expandafter\prebreakpenalty\expandafter`\@i =10000}
\@tfor\@i:=ーぁぃぅぇぉっゃゅょゎァィゥェォッャュョヮヵヶゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ…\do{\expandafter\prebreakpenalty\expandafter`\@i =0}

約物の処理

LaTeXの標準設定では、約物(句読点、括弧、中黒、疑問符・感嘆符など)に関してはベタ組にならない。そこで、さらにベタ組にするためには以下のような工夫が必要である。

まず、LaTeXで約物用のマクロ定義を行なう。続いて、Pythonでプレーンテキストを加工するための関数を定義する(詳しい解説は面倒なので割愛)。

LaTeX側のマクロ定義

%% punctuations
%%%% 句読点
\if@burasage
    \def\、{%
        \@ifnextchar\par{}{\hbox{}}%
    }%
    \def\。{%
        \@ifnextchar\par{}{\hbox{}}%
    }%
\else
    \def\、{\nobreak\makebox[1zw][l]{}}%
    \def\。{\nobreak\makebox[1zw][l]{}}%
\fi
%%%% 疑問符・感嘆符
\newcommand{\QueEx}{\nobreak\<}
\newcommand{\QueQue}{\nobreak\<}
\newcommand{\ExQue}{\nobreak\<}
\newcommand{\ExEx}{\nobreak\<}
\newcommand{\Que}{\nobreak\<}
\newcommand{\Ex}{\nobreak\<}
\newcommand{\ExExExEx}{\nobreak{\tcy{!!!!}}}
\newcommand{\ExExEx}{\nobreak{\tcy{!!!}}}
\newcommand{\zenkakuaki}{\hskip1zw plus .125zw minus 0.03125zw}
\newcommand{\nibusibuaki}{\hskip.75zw plus .125zw minus 0.03125zw}
\newcommand{\nibuaki}{\hskip.5zw plus .125zw minus 0.03125zw}
\newcommand{\minusnibuaki}{\hskip-.5zw plus .125zw minus 0.03125zw}
\newcommand{\sibuaki}{\hskip.25zw plus .125zw minus 0.03125zw}
%%%% その他約物
\def\・{\jghostguarded{\leavevmode\hbox to 1zw{}}}
\def\…{\jghostguarded{\hbox to 2zw{……}}}
\def\.{\jghostguarded{\leavevmode\hbox to 1zw{\raise.6zw\hbox{.}}}}
\def\‐{\jghostguarded{\leavevmode\hbox to 1zw{\hss\rule[-.25H]{.4zw}{.55H}\hss}}}% 必要に応じて使用
\def\:{\ifydir\else\CID{12101}\fi}
%%%% インデント
\parindent=0zw
\newcommand{\normalIndent}{\hskip1zw}
\newcommand{\bracketIndentAmount}[1]{\def\bracketIndent{\hskip#1zw\<}}
\bracketIndentAmount{0.5}

Pythonによる約物の調整

brackets = [
    ['「','」'],['『','』'],['(',')'],['〈','〉'],
    ['【','】'],['〔','〕'],['《','》'],['[',']'],
    ['{','}'],['〝','〟'],['“','”'],['‘','’']
]
exque = [
    ['‼','ExEx'],
    ['⁉','ExQue'],
    ['⁈','QueEx'],
    ['⁇','QueQue'],
    ['!','Ex'],
    ['?','Que'],
    ['!!!!','ExExExEx'],
    ['!!!','ExExEx'],
    ['!!','ExEx'],
    ['!?','ExQue'],
    ['?!','QueEx'],
    ['??','QueQue']
]
kutotens = ['、','。']
def punctuation_replace(x):
    # インデント処理
    for bracket in brackets:
        x = re.sub(r'^'+bracket[0],r'{\\bracketIndent}'+bracket[0],x)
    x = re.sub(r'^ ',r'{\\normalIndent}',x)
    # 閉じ括弧
    for bracket in brackets:
        x = x.replace(bracket[1], bracket[1]+'\\hbox{}')
        x = x.replace(bracket[1]+'\\hbox{}}', bracket[1]+'}')
        x = x.replace(bracket[1]+'\\hbox{}\n', bracket[1]+'\n')
        x = x.replace(bracket[1]+'\\hbox{}\<', bracket[1]+'\<')
        for bracket2 in brackets:
            x = x.replace(bracket[1]+'\\hbox{}'+bracket2[0], bracket[1]+'\\hbox{}{\\minusnibuaki}'+bracket2[0])
            x = x.replace(bracket[1]+'\\hbox{}'+bracket2[1], bracket[1]+bracket2[1])
    # 疑問符と感嘆符
    for y in exque:
        x = x.replace(y[0]+' ','{\\'+y[1]+'\\zenkakuaki\\hbox{}}')
        x = x.replace(y[0],'{'+'\\'+y[1]+'}')
        x = re.sub(r'([0-9a-zA-Z]){\\'+y[1]+'}', r'\1'+y[0], x)
    for bracket in brackets:
        if x.find(bracket[0] or bracket[1]) > -1:
            for z in exque:
                x = x.replace(bracket[1]+'\\hbox{}{\\'+z[1], bracket[1]+'\<'+'{\\'+z[1])
                x = x.replace('{\\'+z[1]+'\\zenkakuaki\\hbox{}}'+bracket[0], '{\\'+z[1]+'\\zenkakuaki\\hbox{}}\\<'+bracket[0])
    # 句点と読点
    for kutoten in kutotens:
        x = x.replace(kutoten, '\\'+kutoten)
        for bracket in brackets:
            x = x.replace('\\'+kutoten+bracket[0], '\\'+kutoten+'\\<'+bracket[0])
            x = x.replace('\\'+kutoten+bracket[1], kutoten+bracket[1])
            x = x.replace(bracket[1]+'\\hbox{}\\'+kutoten, bracket[1]+'\\<\\'+kutoten)
    x = x.replace('\。\。\。', r'。。。')
    # その他約物
    x = re.sub('([^…])(……)([^…])',r'\1\\……\3',x)
    x = x.replace('・','{\\・}')
    x = x.replace('‐','{\\‐}')
    x = x.replace(':','{\\:}')
    x = x.replace('〝','“')
    x = x.replace('〟','”')
    x = x.replace('“','〝\\nobreak ')
    x = x.replace('”','\\nobreak 〟')
    for bracket in brackets:
        x = x.replace('{\\・}'+bracket[0],'\\\\<'+bracket[0])
        x = x.replace(bracket[1]+'{\\・}',bracket[1]+'\\<{\\・}')
    x = x.replace('.', '\\.')
    return x

 

次回に続く)

schedule 2020年4月8日
update 2021年12月10日
local_offer #LaTeX #DTP