ぽよメモ

レガシーシステム考古学専攻

日本語論文をLaTeXで書いてtextlintで校正するテンプレートを作った

はじめに

 この記事の対象者は主に修論・卒論を書く人です。英語論文についてはとくに言及しません。

 初めて論文を書くことはとても大変です。しかし、そのひどい初々しい論文を校正する人はもっと大変です。しかも大抵の学生はいっぱい書いてから見て下さい!とお願いしてきます。もはや何から手を付けて良いかすらわからない……。こんなひどい状況を打破するべく、体裁の指摘を自動でやってくれて、内容の指摘に集中できるようになるテンプレートを用意しました!
 これは実は原型のほとんどが実際にM2の時に研究室内で使っていた物なのですが、

  • 去年は忙しくて公開できるような形に持っていく余裕が無かった
  • でもこのまま忘れてしまうには惜しい
  • ↑を作る上で利用させていただいたOSSのメンテナになったので宣伝したくなった

という事情で今年公開することにしました。Pull Requestお待ちしています。

github.com

テンプレートの使い方

リポジトリをフォークする、又は以下の画像にあるUse this templateというボタンをクリックしてください。

f:id:pudding_info:20201205021153p:plain
Use this templateボタン

Creative Commons Zero(CC0)*1で公開していますので、著作者表記などに配慮することなく自由にご利用頂けます。

テンプレートの特徴

LaTeX on Docker

 Word論文はリジェクト!とまでは言いませんが、こうした自動化の恩恵を受けやすいのは単純なテキストで書けるLaTeXです。分からない人は覚えて下さい。
 昔はLaTeXの環境構築は大変だと言われていました(要出典)。今もこだわると大変ですが、どうしてもヒラギノを使わないと死んでしまう人以外はDockerで構築するのが良いでしょう。WindowsでもMacでもLinuxでも安定した結果を得られます。

 僕は以下のリポジトリで管理し、tagを付ける度にDockerhubでビルドするようにしています。このテンプレートではこのイメージを利用していますが、任意のイメージに差し替えることも出来ます。

github.com

https://hub.docker.com/r/pddg/latex

Makefile

 どんなコマンドを打つか思い出すのが面倒なので、このテンプレートではmakeを使います。Windowsではscoopを使ってmakeをインストールする他、開発環境をWSLに持ってしまうなどがおすすめです。

 make すればpdfができて、 make clean すれば中間ファイル含めて全て削除される、そういうシンプルな世界がオススメです。ちなみにGNU Makeの使い方を解説した僕の資料もあるので、是非使ってみてください。

Git管理

 今は2019年なのでGitで管理してGitHubにpushするのは、もはや特殊でも何でもありません。
 現在はGitHub Actionsという超便利なものがあります。これを使って、このテンプレートでは以下の様なワークフローを組みます。textlintやreviewdogについては後述します。

f:id:pudding_info:20201122223159p:plain
論文執筆のワークフロー

VSCode対応

 Visual Studio CodeMacWindowsLinuxのいずれでもよく使われており、非常に便利なエディタです。加えて、最近はDockerやWSLなどとの連携も強化されており、ポータブルな開発環境の構築が簡単になってきました。VSCodeLaTeX用拡張であるLaTeX WorkshopはビルドをDockerコンテナ内で実行することに対応しており、以下の様な環境をすぐに構築出来ます。

f:id:pudding_info:20201204235728g:plain
VSCodeで編集するときの様子

 PDFからソースへ、逆にソースからPDFの該当箇所へジャンプできます。また、保存時に自動ビルドが走ります。

 Dockerがインストール済みのホストにVSCodeをインストールして、必要なエクステンションを入れれば上の画像のような環境が完成するようになっています。

まとめ

 まずこのテンプレートによって2つの問題が解決します。

  • 環境構築が難しい
    • DockerとVSCodeが使用可能であればすぐにPDFを生成できる
  • 使い方が難しい
    • 最低限 make を覚えていればPDFが生成できる

書き始めるまでに脱落する人をできるだけ救えることができれば幸いです。

 実はもう一つ、タイトルにもある重要な特徴があるので次で紹介します。

textlintで校正する

 論文では全体の体裁を意識して記述する必要があります。基本的に表記揺れや「ですます調」「である調」の混じった文などは許されません。しかし、これらを人間が意識して校正するのは多大な労力を必要とします。そこでこれらについてある程度ツールで指摘出来るようにします。これを実現するのがtextlintです。

github.com

環境構築

 このような校正自体をローカルで実行する必要はないかなと思っています。PushしたときにCIでちゃんと警告されればそれでいいかなと。

 一応Node製のツールなので、LaTeXより楽に環境を整えることができます。単にNode JSをインストールしてnpm installすれば環境構築は完了です。

textlint-plugin-latex2e

 textlintは内部的に文章をASTへ変換して使用します。デフォルトではLaTeXファイルを読み込めないため、このプラグインを利用します。

github.com

昨年メンテナとして加えて頂き、サードパーティー製のLaTeXパーサへの移行のお手伝いをしました。
 textlintのASTとLaTeXパーサが解析したASTをすり合わせる、というような細かい作業をしており、おそらく潜在的なバグがあります。もしうまく動かないときは積極的にissueを上げて頂ければと思います*2

Rule

 textlintで警告を出すために様々なルールを追加していきます。
とは言ってもtextlint-rule-preset-japaneseまたはtextlint-rule-preset-ja-technical-writingをインストールすれば終了です。これはいくつかのルールをまとめたもので、個別のルールに対して設定を書くことも出来ます。全部書くと多すぎるので、言及の必要があるものだけ書きます。

github.com

github.com

これらは様々なルールを一括で導入できて便利な反面、この部分ではこのルールを無視したいと思ったとき、(後述するtextlint-filter-rule-commentsを利用すると)毎回% textlint-disable ja-technical-writing/ルール名として記述する必要があり、ちょっと面倒です。不要なルールがあったり、各ルールの最新版が常に反映されているわけではないなど、自分でルールを管理した方が全体を把握でき便利な場合もあります。とりあえず上記プリセットを突っ込んで使ってみて、不満があるなら自分で再構築するのが良いかと思います。

 各ルールの設定は、上記プリセットを導入している場合と、そこに含まれるルールを個別に導入した場合で書き方が異なります。

導入しているとき

{
    "rules": {
        "preset-ja-technical-writing": {
            "ルール名": {
                "設定名": ""
            }
        }
    }
}

導入していないとき

{
    "rules": {
        "ルール名": {
            "設定名": ""
        }
    }
}

textlint-rule-sentence-length

https://github.com/textlint-rule/textlint-rule-sentence-length

一文当たりの単語数ではなく文字数に制限をかけます。英語の文章を含む場合、ignoreする必要があるかもしれません。

textlint-rule-no-mix-dearu-desumasu

https://github.com/textlint-ja/textlint-rule-no-mix-dearu-desumasu

 である、ですます調を統一します。指定しない場合、全体から見て多い方が優先されるので、論文ではである調に統一します。

{
    "rules": {
        "no-mix-dearu-desumasu": {
             "preferInHeader": "である",
             "preferInBody": "である",
             "preferInList": "である",
             // 文末以外でも、敬体(ですます調)と常体(である調)を厳しくチェックするかどうか
             "strict": true
         }
    }
}

textlint-rule-ja-no-mixed-period

https://github.com/textlint-ja/textlint-rule-ja-no-mixed-period

 「。」と「。」のミスはprh(後述)で修正するため、こちらはどちらかというとそもそも文末のピリオド抜けを検知するために使います。

{
    "rules": {
        "ja-no-mixed-period": {
             "periodMark": "",
             "allowPeriodMarks": [],
             "allowEmojiAtEnd": false,
             // --fix時に直すかどうか
             "forceAppendPeriod": true
        }
    }
}

textlint-rule-no-doubled-joshi

https://github.com/textlint-ja/textlint-rule-no-doubled-joshi

 連続して同じ助詞を使用しないようにします。「AにBにします」みたいな文章に対してエラーを出します。当初全角カンマをうまく取り扱えず誤検知が起きていたため、要望を出して改善して頂きました*3。バージョン3.7.0以降を推奨します。

{
    "rules": {
        "no-doubled-joshi": {
            "min_interval" : 1,
            "strict": false,
            "allow": ["",""],
            "separatorCharacters": [
                ".", "", "", ""
            ],
            "commaCharacters": [
                "", ""
            ]
        }
    }
}

textlint-rule-prh

https://github.com/textlint-rule/textlint-rule-prh

 表記揺れを修正するためのルールです。「.」と「。」、「サーバ」と「サーバー」など、間違えやすい語句を検知して修正します。

{
    "rules": {
        "prh": {
            "rulePaths" :["prh.yml"]
        }
    }
}

表記揺れの一覧とその修正はprh.ymlとして別ファイルに書き込みます。

version: 1
rules:
  # Githubやgithubを修正する
  - expected: GitHub
  # ピリオドとカンマを修正
  - expected:pattern: /[。。]/g
  - expected:pattern: /[、、]/g

LaTeXではリンクがリンクとしてパースされない(単なる文字列として処理される)ため、リンクを含む場所ではignoreする必要があるかもしれません。必要な表現をどんどん足していくことで、表記揺れを自動で検知できるようになります。

Filter

 設定したルールに対して例外を設けることが出来ます。

textlint-filter-rule-whitelist

https://github.com/textlint/textlint-filter-rule-whitelist

 例えばprhでGitHubの誤字を修正したい場合、リンクまで検知してしまうという問題がありましたが、ここでホワイトリスト製で例外を管理できます。他のルールで引っかかった語もこれで排除することが出来ます。

{
    "filters": {
        "whitelist": {
            "allow": [
                "github.com"
            ]
        }
    }
}

textlint-filter-rule-comments

https://github.com/textlint/textlint-filter-rule-comments

 一部だけlintをオフにしたい場合に使えます。

{
    "filters": {
        "comments": {
            "enablingComment": "textlint-enable",
            "disablingComment": "textlint-disable"
        }
    }
}

例えば英文では文字数制限を解除したい場合、以下の様に書きます。

% textlint-disable sentence-length

\section{英語}
    hoge hoge fuga fuga

% textlint-enable sentence-length

\section {日本語}
    ほげほげふがふが

ルール名を指定しない場合、全てのルールを無視します。ルールはカンマ区切りで複数指定することが出来ます。

GitHub ActionsでCI/CD

 textlintしてreviewdogを走らせ、masterにマージしたら自動でPDFをビルド、タグを打つとそれをリリースします。プライベートリポジトリでは

  • Freeアカウント:2000分/月
  • Proアカウント:3000分/月

のビルド時間が無料枠になります*4GitHub Student Developer Packに登録することでPro相当の恩恵を得られるので、大学のメールアドレスを持っている人は登録しましょう*5。また、大学や研究室単位でTeamやOrganizationを使用している場合、上記に当てはまらない可能性があるため、そのOwnerに確認しましょう。

 Travis CIやCircle CIを使う場合と比べて、トークン等を自分で取得・指定する必要がなく楽です。テンプレートにはすでにGitHub Actionsのworkflowが組み込まれており、特に設定することなく自動で実行されます。

Lint

 LaTeXのコードを静的解析し、ルールに違反する文章を検出します。このテンプレートではPull Requestを発行/更新するとこのワークフローがトリガーされるようになっています。このワークフローの実行にはおよそ30~40秒かかります。詳細は .github/workflows/lint.yaml を見てみて下さい。
 違反した文章を修正しやすくするよう、reviewdogからコメントをもらえるようにしています。更新は全てPull Requestを経由することで、masterブランチは常にビルド可能かつルールに違反していない文章のみが存在するようになります。

↓修正箇所をこんな感じで指摘してくれます。

f:id:pudding_info:20191208002634p:plain
reviewdogによるレビュー

Build

 masterブランチへのpushでビルドを実行し、その成果物をアップロードしてダウンロード出来るようにします。1分~1分半程度かかります。

f:id:pudding_info:20191208003135p:plain
ビルドしたPDFのダウンロード

 この成果物はデフォルトでは90日間有効なようです*6。それ以上の期間更新したい場合、次章のようにタグを付けて自動リリースしましょう。

Release

 タグを付けたらGitHub Releasesに新しいリリースを作ってPDFをアップロードします。1分~1分半程度かかります。

f:id:pudding_info:20191208003250p:plain
GitHub ReleasesからPDFをダウンロード

 こちらはファイルの保持期限が特にないため、第一稿、第二稿、完成などのような段階ごとにタグを打っておくと分かりやすくて良いでしょう。

注意点

 インライン数式に$を使用すると大幅なパフォーマンス劣化を生じます。インライン数式は \( x^2 \) のように記述することでパフォーマンス劣化を避け高速にlintを実行できます*7
 $ によるインライン数式が多数利用されたTeXソースに対するlintは全く終わらなくなってしまいます。そのため、同梱しているGitHub Actionsのワークフローではタイムアウトを10分に設定しており、これを超えると強制的にワークフローが終了します。これによりGitHub Actionsの無料ビルド時間を食い潰さないようになっていますので、もしタイムアウトしたらインライン数式によるパフォーマンス劣化を疑ってみて下さい。

原因を特定したので近く修正版を出します。これにより、インライン数式によるパフォーマンス劣化は起きない見込みです。

[追記 2020/12/7] こちらの問題を修正したv1.0.3がリリースされました。こちらのテンプレートもそれに合わせてバージョンアップしv1.0.0をリリースしました。

まとめ

 LaTeXソースを静的解析するtextlintのプラグインを利用することで、校正作業の一部を自動化する方法を示し、そのテンプレートを紹介しました。体裁は自動で指摘し、内容を人が集中してレビューすることでレビュアーの負荷を少しでも下げることができれば幸いです。
 私自身はアカデミアから遠く離れてしまい、既に論文を書く身ではなくなっていますが、textlint-plugin-latex2eへのコントリビュートは続けていきますのでissueやPRお待ちしています。


*1:creativecommons.jp

*2:ただしメンテナーはサポート担当ではないので、それを誤解されませんよう…

*3:https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/26

*4:他のプライベートリポジトリと共有であることに注意が必要です。

*5:https://help.github.com/ja/github/teaching-and-learning-with-github-education/applying-for-a-student-developer-pack

*6:docs.github.com

*7:これを書きながらインライン数式が(textlint-plugin-latex2eの不具合により)ASTを破壊している気がしてきたのでたぶん直します