【LaTeX】句読点をdviの時点で置き換える方法

# dviの時点で句読点を置き換える

LaTeX で論文とかレポートとか書きたいときに句読点を、。ではなく，．にしたいことがあります。IME から句読点を変えればいいじゃんとなりますが、メールとかそういうのでは、。のままにしたいから IME からは変えたくない。あとtexファイルの中の文字は、。のままにしておきたいという願望もあります。

このような場合 usepackage とかしてLaTeX のシステムの中で「、。」を「，．」に置き換えるのが理想ですが、やはり自分のような素人には限界があるようです（[【LaTeX】upLaTeXの句読点を置き換えるパッケージ](https://qiita.com/migawariw/items/928227fb5f7611ec3baa) を参照）。そこで外部コマンド、すなわちlatexmkの中で句読点を変換してしまえば確実なのではないかと考えました。それでもソースのtexファイル中の文字を置き換えることはできません。texファイルでは「、」「。」にしたままpdfでは「，」「．」にするというのが自分の目的なのです。真っ先に思いついたのは

> (ソースファイル名).tex → コピー → (ソースファイル名)_copied.tex → 句読点置き換え・(u)platex →  (ソースファイル名).dvi → dvipdfmx → (ソースファイル名).pdf

なのですが、そのためにlatexmkを使おうとするとコンパイルエラーが出てしまいました。どうやら、インプットファイル名と異なるアウトプットファイル名で出力するという操作は想定されていないようです。

方針を変えて、そもそもu(p)latexで置き換えられればよいのだから**dviの段階で書き換えれば**よいのではないかと考えました。

# dvispc

そうはいっても生のdviはバイナリなので書き換えできません。そこでdviを（人間が読める）テキストに変換でき、かつテキストをdviに変換できる**dvispc**を使います（dvispcはtexlive2022に含まれているようです）。

方法としては
> (ソースファイル名).tex → （複数回）(u)platex → (ソースファイル名).dvi → dvispc → (ソースファイル名).txt → 句読点置換 → dvispc →  (ソースファイル名).dvi → dvipdfmx →  (ソースファイル名).pdf

とします。下はplatexを使う場合の`.latexmkrc`の一例です（uplatexの場合はplatex,pbibtexをuplatex,upbibtexに置き換えてください）。「、」「。」を「，」「．」に置換するものです。なおdviをテキスト化したファイルの中で、「、」「。」「，」「．」はそれぞれ`0x3001` `0x3002` `0xff0c` `0xff0e` に対応します。

`sed`は以下のように使います。

```
sed -i (入力ファイルの末尾に追加して出力ファイルとする文字列) -e s/(置換前の文字列)/(置換後の文字列)/ (入力ファイル)
```

なぜ入力ファイルの末尾に文字を追加して出力する仕様になっているのかは自分にはわかりませんが、これを`""`として何もつけない扱いにすると元のファイルが上書きされます。

あとlatexmkではプレースホルダー（日本語にすると変数？）が使えます。`%O`はオプション、`%S`は入力ファイル、`%D` は出力ファイル、`%R`はファイル名から拡張子を抜いた文字列を表します。dviを変換したファイル名を`%R.txt`にしています。[VSCode で最高の LaTeX 環境を作る](https://qiita.com/rainbartown/items/d7718f12d71e688f3573) の記事のものから`dvipdf`の部分を改造してみました。

```perl:latexmkrc
#!/usr/bin/env perl

# LaTeX
$latex = 'platex -synctex=1 -interaction=nonstopmode -halt-on-error %O %S';
$max_repeat = 5;

# BibTeX
$bibtex = 'pbibtex %O %S';
$biber = 'biber --bblencoding=utf8 -u -U --output_safechars %O %S';

$makeindex = 'mendex %O -o %D %S';

# DVIからPDFにする、ここで句読点を置換する
$dvipdf = 'dvispc %O -a %R.dvi %R.txt && sed -i "" -e s/0x3001/0xff0c/ -e s/0x3002/0xff0e/ %R.txt && dvispc %O -x %O %R.txt %R.dvi && dvipdfmx %O -o %D %S';
$pdf_mode = 3;

# preview
$pvc_view_file_via_temporary = 0;
if ($^O eq 'linux') {
$dvi_previewer = "xdg-open %S";
$pdf_previewer = "xdg-open %S";
} elsif ($^O eq 'darwin') {
$dvi_previewer = "open %S";
$pdf_previewer = "open %S";
} else {
$dvi_previewer = "start %S";
$pdf_previewer = "start %S";
}

# 下の方まで探してくれる
$ENV{'TEXINPUTS'}='.//:' . $ENV{'TEXINPUTS'};

# clean up
$clean_full_ext = "%R.synctex.gz"
```


<!-- ちなみにVSCodeの`setting json`に書き込む場合はこうします。 -->

この`latexmkrc`を文書ごとに準備してやれば文書単位で句読点を副作用なく指定して使うことができます。もしローカル環境をお使いの方であれば、ホームディレクトリ直下にこのファイルを入れておけばソースのフォルダに`latexmkrc`を入れていなくても`latexmk`コマンドをそのまま使えば句読点が置換されるようになります。

また、逆に「このファイルでは句読点を置換したくない！」となった場合はそのソースのフォルダに

```perl
$dvipdf = 'dvipdfmx %O -o %D %S';
```

だけ書いた`latexmkrc`を入れておけば変数`dvipdf`の内容が上書きされてそのフォルダ内では句読点が置換されません。

なお Overleaf を使っている場合はこの方法は使えません。どうやらdviの名前が元ファイルの名前によらずoutput.dviになるためのようです。`%R`の部分をうまくかえるとできるかもしれません。

# settings.jsonから使う場合（VSCode）

ほとんど同じですが一応書いておきます。

```settings.json
{
"latex-workshop.latex.tools": [
			{
				"name": "platexmkkutoten",
				"command": "latexmk",
				"args": [
					"-e",
					"$latex=q/platex -synctex=1 -interaction=nonstopmode -halt-on-error/",
					"-e",
					"$bibtex=q/pbibtex/",
					"-e",
					"$biber=q/biber --bblencoding=utf8 -u -U --output_safechars/",
					"-e",
                    "$pdf_mode=3",
                    "-e",
					"$dvipdf=q/dvispc %O -a %R.dvi %R.txt && sed -i '' -e s\\/0x3001\\/0xff0c\\/ -e s\\/0x3002\\/0x3002\\/ %R.txt && dvispc %O -x %O %R.txt %R.dvi && dvipdfmx %O -o %D %S/",
					"-e",
					"$makeindex=q/mendex %O -o %D %S/",
					"%DOCFILE%.tex",
					"-e",
					"$ENV{'TEXINPUTS'}='.//:' . $ENV{'TEXINPUTS'}"
				]
			},
		],
"latex-workshop.latex.recipes": [
			{
				"name": "latexmk",
				"tools": ["latexmk"]
			}
		]
}
```


快適な句読点ライフを！

# （2022/09/08追記）Overleafでの方法

Overleaf で使う場合はファイル名の都合から上の方法は使えません。[latexmk による LaTeX ワークフロー内で句読点を自動で置換する](https://qiita.com/yudai-nkt/items/900a5f1c87689e033ff3)の記事を参考にこちらの`.latexmkrc`を作ってみました。この方法を使うと自分のパソコンでは「ソースでは[、。]のまま pdf では[，．]にする」が達成できました。


```perl:.latexmkrc
#!/usr/bin/env perl

# LaTeX

$latex = "perl -pi -e 's/、/，/g' ./*.tex && perl -pi -e 's/。/．/g' ./*.tex && platex -synctex=1 -halt-on-error -file-line-error";

# BibTeX
$bibtex = 'upbibtex %O %S';
$biber = 'biber --bblencoding=utf8 -u -U --output_safechars %O %S';

# index
$makeindex = 'mendex %O -o %D %S';

# DVI / PDF句読点の変更
$dvipdf = 'dvipdfmx %O -o %D %S';
$pdf_mode = 3;

# preview
$pvc_view_file_via_temporary = 0;
if ($^O eq 'linux') {
$dvi_previewer = "xdg-open %S";
$pdf_previewer = "xdg-open %S";
} elsif ($^O eq 'darwin') {
$dvi_previewer = "open %S";
$pdf_previewer = "open %S";
} else {
$dvi_previewer = "start %S";
$pdf_previewer = "start %S";
}

#下の方まで探してくれる
$ENV{'TEXINPUTS'}='.//:' . $ENV{'TEXINPUTS'};

# clean up
$clean_full_ext = "%R.synctex.gz"
```


# 参考文献

[latexmk による LaTeX ワークフロー内で句読点を自動で置換する](https://qiita.com/yudai-nkt/items/900a5f1c87689e033ff3)
[VSCode で最高の LaTeX 環境を作る](https://qiita.com/rainbartown/items/d7718f12d71e688f3573)