【LaTeX】upLaTeXの句読点を置き換えるパッケージ

# 注意

:::note warn
（2022/09/08 追記）この記事にある switchkutoten パッケージはこちらのツイートで触れられているように"3000や"FF00のブロックの文字を丸ごと欧文扱いにするものなので、使う場合はその意味を把握した上でお使いください。 doraTeX さんの[upLaTeX文書の句読点を置き換える](https://doratex.hatenablog.jp/entry/20220907/1662553045)や、私がこの記事の後に書いた[【LaTeX】句読点をdviの時点で置き換える方法](https://qiita.com/migawariw/items/30bb1745fcf2e7d4d8b1) の方法の方が TeX 的には安全だと思います。
:::


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">面白いんだけど、ただこの<br>「&quot;3000や&quot;FF00のブロックを欧文扱いにする」<br>というギミックについては<br>「根本的に危険であって、完璧にする（完全に副作用をなくす）ことはまず無理」<br>ということを、使う人が確実に把握しておくべきだとも思う🙂<a href="https://twitter.com/hashtag/TeX?src=hash&amp;ref_src=twsrc%5Etfw">#TeX</a> <a href="https://twitter.com/hashtag/TeX%E8%A8%80%E8%AA%9E?src=hash&amp;ref_src=twsrc%5Etfw">#TeX言語</a></p>&mdash; 某ZR（ざんねん🙃） (@zr_tex8r) <a href="https://twitter.com/zr_tex8r/status/1567470349683671040?ref_src=twsrc%5Etfw">September 7, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# はじめに

自分は文書を作る時にupLaTeXを使っていますが、ふと句読点に、。ではなく，．を使いたくなるときがあります（このページは、。で書いていますが…）。upLaTeXで句読点を，．にするには以下の方法が考えられます。

- IMEの設定で句読点を，．に変更
- コンパイルのタイミングでそのtexファイル中の、。を，．に変更
- フォントマップを変更
- `newunicodechar`パッケージを使って、。を，．に再定義する。

上の3つはそれぞれ
- IMEの設定を変更するのはメール等ふと、。を使いたくなる状況があるので怖い
- コンパイルのレシピとして変更するのは、他人のファイルの内容を改変してしまう危険がある
- フォントマップの変更がそもそも（LaTeXのフォント周りの知識が少ない自分には）ハードルが高いのと個別のフォントごとにしなくてはならないのが面倒、新しくフォントを増やしたら忘れそう

というデメリットがあるのと、そもそも文書単位で句読点を変えたいというのが自分の希望なので4つ目の方法、`newunicodechar`を使う方法を採用します。

# 再定義の方法

`newunicodechar`はplatexでは使えません。upLaTeXでは使えます。LuaLaTeXでも使えます。

## LuaLaTeXの場合

プレアンブルに以下を追加。

```latex
\usepackage{newunicodechar}
\newunicodechar{、}{，}
\newunicodechar{。}{．}
```

これだけです。「、」を「，」に「。」を「．」に置き換える前提で書きました。違う組み合わせにしたい場合は適宜置き換えてください。副作用は自分が見たところありません。


## upLaTeXの場合

upLaTeXでは和文文字は`\newunicodechar`できないという制限があるので一旦「、」（U+3001）「。」（U+3002）が含まれるunicodeブロックの文字の`kcatcode`を`15`、すなわち欧文扱いとします（ブロック単位でしか変えられません）。このためブロックに含まれる文字（括弧類も含む）を全て再定義する必要があります。

「、」を「，」に「。」を「．」に置き換える場合は

```latex
\usepackage{newunicodechar}
\kcatcode"3000=15
\newunicodechar{、}{，}
\newunicodechar{。}{．}
```

と行きたいところですが、こうすると副作用があります。


<!-- なお逆に「，」「．」を「、」「。」に置き換える場合は

```latex
\usepackage{newunicodechar}
\kcatcode"FF0E=15
\newunicodechar{，}{，}
\newunicodechar{．}{}
``` -->

例えば次の文書を出力したいとします。

```latex
\documentclass[a4j,12pt,uplatex,dvipdfmx]{jsarticle}
\parindent=0em
\pagestyle{empty}
\renewcommand{\baselinestretch}{0}
\begin{document}
普通の文; です．そこで

合字; ．．．

直後に数字; ．1

改行を挟む; です．
あれは
\end{document}
```


![switchkutotenimg2-nt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/44121b9e-8d64-4e91-c127-0439f8b88a41.png)
`newunicodechar`使うとこうなります。

```latex
\documentclass[a4j,12pt,uplatex,dvipdfmx]{jsarticle}
\parindent=0em
\pagestyle{empty}
\renewcommand{\baselinestretch}{0}
\usepackage{newunicodechar}
\kcatcode"3000=15
\newunicodechar{、}{，}
\newunicodechar{。}{．}
\begin{document}
普通の文; です。そこで

合字; 。。。

直後に数字; 。1

改行を挟む; です。
あれは
\end{document}
```

![switchkutotenimg-nt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/901e9751-6b9d-f1a5-3125-b6e0a17c936c.png)
。の後に改行を挟んだときに「．」と「あ」の間に半角スペースが入ってしまいます。

`\newunicodechar`の2行を修正してみます。

```latex
\newunicodechar{、}{\char"FF0C}
\newunicodechar{。}{\char"FF0E}
```

![switchkutotenimg3-nt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/5a48527d-c058-1638-f5e8-90d3f7b2c85c.png)
今度は直後に数字があると文字化けしてしまいました。これは`char`が`"FF0E1`という16進法の数字と勘違いしたからです。直後に数字またはAからFまでのアルファベットを入れても同じことが起こります。

今度は後ろに空白を入れてみましょう。

```latex
\newunicodechar{、}{\char"FF0C }
\newunicodechar{。}{\char"FF0E }
```

![switchkutotenimg4-nt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/0f3f1e5c-87e5-386b-8340-63c92f088a36.png)
初めと同じように改行を挟むと空白が入ってしまいました。


spaceを強制的に無視する`ignorespaces`を入れてみましょう。

```latex
\newunicodechar{、}{\char"FF0C\ignorespaces}
\newunicodechar{。}{\char"FF0E\ignorespaces}
```

![switchkutotenimg5-nt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/57c1af55-9bdb-df33-4259-f2a47811156b.png)
合字がダメになってしまいました。合字が使えないと何が困るのかというと例えば（いささか強引な文ですが）

> 彼は「『やる！僕も。』」と言った。

のような文章を出力したときにこうなります。上が合字ありの出力、下が合字なしの出力です。
![switchkutotenimg7-nt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/9415c020-bcbf-b11e-fdf3-5131cd412443.png)
![switchkutotenimg6-nt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/6abcacf4-0ace-dbec-ca57-a9534233c8e3.png)
`\kcatcode`でカギ括弧類と普通の括弧も定義しなおされてしまう（定義しなければならない）のでignorespacesすると下のようになってしまう欠点があります。ということでこの手は使えません。

結局色々試行錯誤したのですが、合字できない、直後の数字で文字化け、改行が空白になる、の3つの副作用はどうしてもどれか1つ残ってしまうことがわかりました。ちなみに試したものは以下です。

後ろに代入したもの

- `\relax`
- `\empty`
- `\space`
- `\@ifnextchar`による条件分岐
- `\@ifx\@nextchar=\par`による条件分岐
- `{}`
- よくわからないけど`\expandafter`

`\char`の代わりに使ったもの
- `\UTF`
- `\Uchar`
- `\CID`
- `\symbol`
- `\Ucharcat`

その他
- expl3文法 なんかエラーが出た
- `xparse`パッケージの`\DeclareDocumentCommand`

~~そもそも`\char`がどこまで数字とみなすかをはっきりさせることができれば済む話なのですが…なんでこんなひどい仕様になっているのかがわかりません。~~

# switchkutoten パッケージ

[switchkutoten パッケージ](https://github.com/migawariw/switchkutoten)を作ってみました。このパッケージを読み込むとupLaTeXでも3つの副作用のいずれか付きではありますが、句読点を自由に変換できます。あと警告がうるさいので`\newunicodechar`ではなくその元の定義になっている`\@namedef`を使用しています。ちなみに途中で

- `\char`が"をつけなければ10進数のunicodeを出すこと
- `\Ucharcat 10進数コード 文字コード`で出力すると「直後に数字」の文字化けが起こらない代わりにコンパイルエラーで済む（自分の中でも文字化けとコンパイルエラーのどちらがいいのか賛否両論ありますが…）

という事情から`\Ucharcat`を使用しています。
パッケージオプションには以下があります。
- nothing 句読点の組み合わせを変更しない
- cp 「。」「、」を「．」「，」に変更
- cmaru 「．」「、」を「。」「，」に変更
- tenmaru 「．」「，」を「。」「、」に変更
- tenp 「。」「，」を「．」「、」に変更
- empty 直後に何も入れない（。とかの直後に数字があるとエラーになる）
- forcezenkaku 直後に`\ignorespaces`挿入（合字なし）
- space 直後にスペース挿入（「。」「．」直後の改行が空白）

があります。デフォルトでは`nothing`、`empty`になっているので「`forcezenkaku`または`space`なしでコンパイルできる」ならば「余計な空白、文字化け等入らず正しい出力になっている」ようになっています。

なお自分は`〜です。1日目は…`みたいなのが出てくる文章では`space`にして`。`の次に改行が出たらシンタックスハイライトするようにVSCodeを設定して、そうでない数学とかのレポートでは`empty`にしています。

誰か副作用なく(u)pLaTeXの中でパッケージとして変換する方法がわかる方がいらっしゃればご教示いただけると幸いです。



# （追記 2022/09/08）CMapファイルから置き換える方法

https://doratex.hatenablog.jp/entry/20220907/1662553045

doraTeX さんの記事で本記事を紹介していただきました！ ありがとうございます！

上の記事の方法を使うとCMapファイルから、本記事のような副作用なしで[、。]を[，．]に置き換えることができました。

# （さらに追記 2022/09/08）dvi の時点で置き換える方法

doraTeX さんの記事と前後するタイミングで「pLaTeX と upLaTeX で置き換えられればよいのだから dvi の段階で置き換えればよいのでは」と思い、[【LaTeX】句読点をdviの時点で置き換える方法](https://qiita.com/migawariw/items/30bb1745fcf2e7d4d8b1) を投稿しました。こちらは latexmkrc を使う方法です。こちらも本記事のような副作用なしで[、。]を[，．]に置き換えることができる方法だと思うのでぜひご覧ください。

# コードハイライトでミスを減らす（一応）

switchkutoten パッケージの`space`オプションを使うときは「。」の直後に改行してスペースを空けてしまう「ミス」を減らすために特にVSCodeを使用している人であれば次のようなコードハイライトをするといいと思います。VSCodeの[`Highlight`](https://marketplace.visualstudio.com/items?itemName=fabiospampinato.vscode-highlight)という拡張機能を使っています。

```setting.json
{
"highlight.regexes": {
		"(。\n)": [
			{
				"border": "1px solid red"
			}
		],
		"(。\n\n)": [
			{
				"border": "1px solid #1E1E1E"
			}
		],
		"(。\n\\\\begin)": [
			{
				"border": "2px solid #1E1E1E"
			}
		],
		"(。\n\\\\end)": [
			{
				"border": "2px solid #1E1E1E"
			}
		],
		"(。\n\\\\item)": [
			{
				"border": "2px solid #1E1E1E"
			}
		],
	},
}
```

長く書きましたが要は「。」の後の改行直後に`begin` `\end` `\item` `\n`（改行）のいずれかがこなければ文字を赤い枠で囲むというだけのものです。結構使えます。正規表現を使います。

本当は下の4つは「または」の正規表現を使って一つにまとめたかったのですが、いじっていたら何回かVSCodeが落ちたのでできませんでした。