LoginSignup
10
6

More than 5 years have passed since last update.

texの分割ファイルを統合して出力するスクリプトを書いたら論文執筆速度が爆速になった話

Last updated at Posted at 2019-01-11

texの分割ファイルについて

texには、ファイルを分割して作業効率が上がるpackageがあります。\input\includeはファイルを分割することが可能ですが、分割したファイル単体でコンパイルするとエラーを吐かれます。そこで、分割されたファイルでもコンパイルエラーを吐かないsubfilesを用いたファイル分割を個人的に使ってます。
subfilesの書き方などについてはこちらの記事を御覧ください。
分割した LaTeX ファイルを subfiles を使ってコンパイルする

ただこの記事でも書かれていますが、子ファイルで\ref\citeを用いると,?? や [?] のように出力されてしまう現象が起きます。

master.tex
\documentclass[uplatex]{jsreport}

\usepackage{subfiles}

\begin{document}
% chapter1
\subfile{./sub1.tex}

% chapter2 
\subfile{./sub2.tex} 
\end{document}
sub1.tex
\documentclass[master.tex]{subfiles}

\begin{document}

\chapter{sub1ファイルだよ\label{chap:sub1}}
hello sub1.
\end{document}
sub2.tex
\documentclass[master.tex]{subfiles}

\begin{document}

\chapter{sub2ファイルだよ\label{chap:sub2}}
hello sub2.
% 本当はここでsub1の章を参照してほしいけどsubfilesだとそれができずに??になっちゃう\ref{chap:sub1}章の後にくる章だよ
\end{document}

個人的にもこの問題に悩んでいて、参照している部分はすべて同じファイル内に無理やり記述してました。見返すと超汚いファイル分割になっていて、なんとかならないもんかといろいろ考えました。

そこで

そこで、「じゃあ自分で好きなようにファイルを分割した上でwebpackみたいに一つのファイルにまとめてくれれば、まとまったファイル上ではこの問題解決するんじゃね」って思ったわけです。

具体的にはこんな感じ

master.tex
\documentclass[uplatex]{jsreport}

\usepackage{subfiles}

\begin{document}
% chapter1
\subfile{./sub1.tex}

% chapter2 
\subfile{./sub2.tex} 
\end{document}
sub1.tex
\documentclass[master.tex]{subfiles}

\begin{document}

\chapter{sub1ファイルだよ\label{chap:sub1}}
hello sub1.
\end{document}
sub2.tex
\documentclass[master.tex]{subfiles}

\begin{document}

\chapter{sub2ファイルだよ\label{chap:sub2}}
hello sub2.
第\ref{chap:sub1}章の後にくる章だよ
\end{document}

この3つのファイルから

output.tex
\documentclass[uplatex]{jsreport}

\usepackage{subfiles}

\begin{document}
% chapter1
\chapter{sub1ファイルだよ\label{chap:sub1}}
hello sub1.

% chapter2 
\chapter{sub2ファイルだよ\label{chap:sub2}}
hello sub2.
% これなら\ref{chap:sub1}をちゃんと参照してくれる\ref{chap:sub1}章の後にくる章だよ

\end{document}

こんなtexファイルを自動生成してくれたら\ref\citeoutput.tex上で正しく参照してくれそうです。

ということで作りました

Goの勉強をしたかったので、試しにGo言語で書いてみました。なんかもっと良い書き方あったらコメントで教えてください。今までjsで脳死動的型付けしてた身としては、コーディングでやたらコンパイルエラー出まくっていろいろストレス溜まったけれど、Goは書き方がみんな一緒になるっている理由が何となくわかった気がしました。あとテンプレートリテラル使いたい人生だった。
やってることはたいしたことないです。subfiles自体、\subfile{}でファイルのパスを指定しているのでそのファイルオープンして中身を全部output.texに流し込んでるだけ。メソッドわけはめんどいんでしてませんがあしからず。

MargeTex.go
package main

import(
    "fmt"
    "os"
    "bufio"
    "strings"
    "flag"
)
func main(){
    // masterファイルとoutputファイルをオープン
    mainName := flag.String("m", "master.tex", "master file")
    outputName := flag.String("o", "dist.tex", "output file")
    flag.Parse()

    file, err := os.Open(*mainName)
    if err != nil {
        fmt.Printf("failed to open inputfile")
    }

    outputFile, err := os.OpenFile(*outputName, os.O_WRONLY, 0666)
    if err != nil {
        fmt.Printf("failed to open outputfile")
    }

    scanner := bufio.NewScanner(file)
    sumText := ""
    // masterファイルを一行ずつ見ていく
    for scanner.Scan() {
        text := scanner.Text()
        fileStr := "subfile{"

        // 子ファイルを呼び出している行を見つけたらその子ファイルの中身をコピーしてoutputファイルに書き込み
        if strings.Contains(text, fileStr) {
            filePath := text[9:len(text)-1]

            subfile, err := os.Open(filePath)
            if err != nil {
                fmt.Printf("failed to open file")
            }
            scanner := bufio.NewScanner(subfile)

            isActive := false

            // begin{document}からend{document}の間の行だけコピー
            for scanner.Scan() {
                subtext := scanner.Text()
                if strings.Contains(subtext, "end{document}") {
                    isActive = false
                }
                if isActive {
                    sumText += (subtext + "\n")
                }
                if strings.Contains(subtext, "begin{document}") {
                    isActive = true
                }
            }
            if err = scanner.Err(); err != nil {
                fmt.Printf("failed to read file")
            }
        } else {
            sumText += text
        }
    }
    if err = scanner.Err(); err != nil {
        fmt.Printf("failed to read file")
    }
    fmt.Fprintln(outputFile, sumText)
}

そして
go run MargeTex.go -m path/to/master.tex -o path/to/output.tex
をすればmaster.tex含め、呼び出している子ファイルも全部まとまったoutput.texが生成されます。

結果

素晴らしいtexファイル分割ライフが始まりました。
副産物として、どこかにtexファイルを提出する事になったときはこの出力texファイル一つを提出すればいいだけので提出する際にも便利ですね。

githubにも載せましたので、寄った方はぜひスターつけて帰ってください(笑)。
それではみなさんも快適なtexファイル分割ライフをノシ

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6