LaTeXで載せたプログラムソースがページを跨ぐ場合の対処法について

はじめに

私はとある大学に通う情報系の学生なのですが,レポートをLaTeXで書くことが多々あります.
情報系の演習ではレポートにプログラムのソースコードを載せることがあります.
しかし,ソースコードが長くて1ページに収まりきらないこともよくあります.
その時,LaTeXでははみ出した部分のソースを正常に表示してくれないことがあります.
はみ出した部分は自動的に改ページしてくれないのです.
そんな時の対処法をここでは環境,コマンド別に紹介していきます.

今回対象となる環境,コマンド

  • itembox + verbatim
  • listing
  • minted

    itembox + verbatim

    私が1年生の時に受講していた演習においてレポートにソースを載せる際はこの方法でした.
    最初からある環境のみを使用しているので簡単です.
    しかし,ソースがページを跨ぐ場合ははみ出てしまい,次のページに表示してくれません.
    他の学生は一旦itemboxを切って,次のページで新しいitemboxで囲んだりしたりしてました.
    実はあるパッケージを導入すればページを跨いだ場合でも自動的にitemboxを改ページしてくれるのです.

    breakitembox

    itemboxに代わる,breakitemboxという環境を使えばページを跨いだ場合でもきちんと対処してくれます.

    導入方法

  • 以下のパッケージを全てダウンロードする.
    • itembkbx.sty
    • itembbox.sty
    • emathC.sty
    • jquote.sty
    • eclbkbox.sty
  • \usepackage{itembkbx}で読み込む.
  • 使う

パッケージはCTANにはないのでgithubからダウンロードしましょう.
github.com
パッケージを全てダウンロードしたらそれらを全て読み込める状態にします.

texファイルと同じディレクトリに置く

breakitemboxを使いたいtexソースと同じディレクトリに先程ダウンロードしたパッケージを置きます.

$TEXMFHOMEに置く

$TEXMFHOMEの場所を把握します.

kpsewhich -var-value $TEXMFHOME

パスが返ってくるのでその中にtexディレクトリを作ります. デフォルトでは以下のようになっていると思います.

~/texmf/tex

その直下にパッケージを置きます. 置いたら次のコマンドで更新します.

mktexlsr [$TEMFHOMEが設定されているパス] # ex) mktexlsr ~/texmf

使い方

使い方はitemboxとさほど変わりません.

\begin{breakitembox}[l]{見出し}
    \begin{verbatim}
        #include<stdio.h>
        int main(void){
            printf(Hello World!\n);
            return 0;
        }
    \end{verbatim}
\end{breakitembox}

このようにすると以下のような結果が得られます. f:id:muscle_keisuke:20160211170919p:plain
行数が多いプログラムはファイルから読み込みましょう.
verbatimパッケージを読み込んでverbatiminputコマンドを使います.

\begin{breakitembox}[l]{見出し}
   \verbatiminput{test.c}
\end{breakitembox}

また,ページを跨ぐ場合にはこんな感じになります. f:id:muscle_keisuke:20160211173512p:plain f:id:muscle_keisuke:20160211173508p:plain

listing

listingはbreakitemboxとは違いソースコードを載せる専用のパッケージです. こちらはデフォルトでページを跨いだ時の処理をしてくれる便利なパッケージです.
使用するパッケージはlistings,jlistingの2つです.
listingsはtexlive2015の時点では最初から入っているようなのでダウンロードはする必要ありません.
ない人はCTANからダウンロードしましょう.
CTAN: Package listings
jlistingはlistingsに日本語対応させる為のパッケージなので入れておきましょう.こちらからダウンロードします.
Listings - MyTeXpert
ダウンロードしたら$TEXMFHOMEに入れて使ってみます.

使い方

まずはプリアンブル部にlistingの設定を書きます.

今回はlisting中心の記事ではないので以下をコピペして使ってください.

\usepackage{listings,jlisting}
\usepackage{color}
\lstset{%
  language={C},
  basicstyle={\small},%
  identifierstyle={\small},%
  commentstyle={\small\itshape\color[rgb]{0,0.5,0}},%
  keywordstyle={\small\bfseries\color[rgb]{0,0,1}},%
  ndkeywordstyle={\small},%
  stringstyle={\small\ttfamily\color[rgb]{1,0,1}},
  frame={tb},
  breaklines=true,
  columns=[l]{fullflexible},%
  numbers=left,%
  xrightmargin=0zw,%
  xleftmargin=3zw,%
  numberstyle={\scriptsize},%
  stepnumber=1,
  numbersep=1zw,%
  lineskip=-0.5ex%
}

それでは実際に使っていきます.

\begin{lstlisting}[caption=test,label=test]
   #include<stdio.h>
   int main(void){
       printf("Hello World!\n");
       return 0;
   }
\end{lstlisting}

このように出力されます.
f:id:muscle_keisuke:20160211184701p:plain
ページをまたいでも大丈夫です. f:id:muscle_keisuke:20160211185216p:plain
ソースコードをファイルから読む場合は以下のようにしましょう.

\lstinputlisting[caption=aaa,label=aaa]{test.c}

minted

このパッケージもまたソースコードを載せるためのパッケージです.
導入方法は過去の記事にあるのでそちらを参考にしてください.
muscle-keisuke.hatenablog.com
mintedもlisting同様ページを跨いだ時に適切な処理をしてくれます.

\begin{minted}{c}
   #include<stdio.h>
   int main(void){
       printf("Hello World!\n");
       return 0;
   }
\end{minted}

出力は以下の通りです.
f:id:muscle_keisuke:20160211194141p:plain
ページを跨ぐ時でもこのように適切に処理してくれます.
f:id:muscle_keisuke:20160211193806p:plain

注意点

mintedは確かにデフォルトでページを跨ぐ処理をやってくれるのですが,ある条件下ではそれが働かなくなります.それは
- キャプションをつけるためにlisting環境を使った時,
- ソースコードを載せる部分の背景色を指定した時
です.
このいずれかの条件が入っている時出力は次のようになります.
f:id:muscle_keisuke:20160211205932p:plain
ページ末尾にあるページ番号を超えてコードが出力されているのが分かります.
これを防ぐために次の環境,コマンドを使います.
- mdframed ...背景色が使えない代わりの枠組み
- captionof ...listing環境が使えない -> キャプションを付加できない よってその代わり
mdframed環境はmdframedパッケージで,captionofコマンドはcaptionパッケージで読み込みます.どちらもtexlive2015には標準で入っているはずですが,ない場合はCTANから
CTAN: Package mdframed
CTAN: Package caption
使い方は以下の通りです.

\definecolor{bg}{rgb}{0.95,0.95,0.95}
\begin{mdframed}[
    backgroundcolor=bg,
    topline=false,
    bottomline=false,
    leftline=false,
    rightline=false]
    \begin{minted}{c}
        #include<stdio.h>
        int main(void){
            printf("Hello World!\n");
            return 0;
        }
    \end{minted}
\end{mdframed}
\captionof{listing}{テストキャプション}

最初の行でdefinecolorコマンドを使っていますが,これは背景色を定義しています.definecolorコマンドはcolorパッケージの中ですので読み込むのを忘れずにしてください.
minted環境をmdframed環境で囲んでください.
mdframed環境のオプション引数ですが,
backgroundcolor=定義したもしくはデフォルトで定義されている色
で背景色を設定できます.
その後の引数は単純にmdframedの枠線を出力しない為の設定です.
(mintedでも枠線を定義できるので重複する)
下から二番目のところでcaptionofコマンドを使ってキャプションを設定しています.第二引数にキャプションの文を書きます.
第一引数のlistingという部分はキャプションの種類です.主に使うものを以下にまとめます.
- listing ...ソースコードなどを載せる時のキャプション
- figure ...グラフや図を載せる時のキャプション
- table ...表を載せる時のキャプション
という感じです.
captionofコマンドではなく通常のcaptionコマンドでつけたキャプションとの番号のずれはなくそこらへんはうまくやってくれます.
実行すると以下のように出力されます.
f:id:muscle_keisuke:20160211212414p:plain
ページを跨いだ場合でも大丈夫です.
f:id:muscle_keisuke:20160211222351p:plain

まとめ

itembox+verbatimを使って長いソースコードをぶつ切りにしてた人は
breakitembox+verbatiminputを使いましょう.
また,listingやmintedを使えばデフォルトでページを跨ぐ処理を適切に行います.
ただし,mintedでページを跨がない場合はmdframedとcaptionofを駆使して解決しましょう.