Macのターミナルでテキストファイルを整形する

# はじめに

「この文書を形態素解析してくれ」とか言われてShift_JISテキストやらdocxやらrtfやらの詰め合わせを渡されたときに役に立ちそうなコマンドラインツールのまとめ。

## 命名ルールに違反しているファイル名を探す

GNUツールのfindを使う。MacのfindはGNUのfindとは違うのでbrewでインストールする。gfindという名前で使えるようになる。

```{zsh}
% brew install findutils
```

gfindで指定したフォルダ以下のファイル名一覧を取得し、grep -vで指定したパターン以外のファイルのみを出力する。textdirという名前のフォルダ内で、19A1M-000001.txtのような名前になっていないファイルを探すときは次のようにする。

```{zsh}
% gfind textdir -type f | grep -v '\d\d[A-Z]\d[MF]-\d\{6\}\.txt$'
```

gfindの-type fオプションはファイルのみを検索結果に含める(フォルダは含めない)。grepの-vはパターンにマッチしない文字列のみを出力する。'...'で囲まれた範囲はパターンを表す正規表現。正規表現は処理系によって多少の違いがあるが、ここでは以下の表現を含む。

|表現|意味|
|---|---|
|\d|半角数字1文字。[0-9]と同じ。|
|[A-Z]|AからZまでの任意の1文字。|
|[MF]|MまたはFのどちらか1文字。|
|\d\\{6\\}|半角数字6文字。|
|\\.|.は正規表現で特殊な意味(何でもいいので1文字)を持つので、通常の文字としての.を表現するときは\\.とする。|
|$|行末を意味する記号。行頭は^|

## 拡張子のないファイルに拡張子を追加する

Macの場合はコマンドラインツールを使わなくてもFinderで簡単に一括追加できる。拡張子を追加したいファイルを全て選択して右クリック(またはcontrol+クリック)でコンテキストメニューを開き、名称変更を選択。「テキストを追加」を選んで.txtを名前の後に追加する。そのままだとファイル１つ１つについて拡張子を変更するか確認ウィンドウが出てしまうので、Finderの環境設定→詳細を開いて「拡張子を変更する前に警告を表示」のチェックを外しておくとよい。

または後述するtextutilでtxtに変換する処理をすれば勝手に.txtをつけてくれると思うのでそれでもいいかも(拡張子なしファイルもそのまま残ってしまうが)。

## ファイルの種類やエンコーディングを調べる

fileコマンドを使う。多くの種類のファイルを判別でき、テキストファイルについてはエンコーディングや改行文字も判別できる。Shift_JISは判別できずNon-ISO extended-ASCIIになる。

```{zsh}
% file *
adobe.pdf:     PDF document, version 1.7 (password protected)
folder:        directory
richtext.rtf:  Rich Text Format data, version 1, ANSI, code page 932
sjis_crlf.txt: Non-ISO extended-ASCII text, with CRLF line terminators
utf8_lf.txt:   UTF-8 Unicode text
word.docx:     Microsoft Word 2007+
```

textutilコマンドを使う。テキストファイルの他、Wordファイルやリッチテキストも判別できるが、pdfやフォルダはエラーになる。

```{zsh}
% textutil -info *
Error reading adobe.pdf.  Text encoding Unicode (UTF-8) isn’t applicable.
Error reading folder.  The file “folder” couldn’t be opened.
File:  richtext.rtf
  Type:  rich text format (RTF)
  Size:  494 bytes
  Length:  9 characters
  Contents:  サンプルテキスト

File:  sjis_crlf.txt
  Type:  plain text
  Size:  18 bytes
  Length:  10 characters
  Contents:  サンプルテキスト

File:  utf8_lf.txt
  Type:  plain text
  Size:  25 bytes
  Length:  9 characters
  Contents:  サンプルテキスト

File:  word.docx
  Type:  Office Open XML format
  Size:  12153 bytes
  Length:  10 characters
  Author:  aadiimmz
  Last Editor:  aadiimmz
  Created:  2021-02-10 06:36:00 +0000
  Last Modified:  2021-02-10 06:42:00 +0000
  Contents:  サンプルテキスト...
```

nkfを使う。エンコーディングと改行コードを判別できる。テキストファイル以外はBINARYになる。

```{zsh}
% nkf --guess *
adobe.pdf: BINARY
richtext.rtf: ASCII (LF)
sjis_crlf.txt: Shift_JIS (CRLF)
utf8_lf.txt: UTF-8 (LF)
word.docx: BINARY
```

## テキストファイルに変換する

textutilを使う。txt、rtf、html、docxなどを相互に変換できる。pdfは変換できない。変換後のテキストファイルはUTF-8で、改行文字は変換されない。*で複数ファイルを一括して変換でき、変換後のファイルは元ファイルの拡張子を.txtにした名前になる。もともと.txtのファイルを変換したときは上書きされる。

```{zsh}
% textutil -convert txt *
```

ファイルを1つずつ変換する場合は、変換後のファイル名を指定することもできる。

```{zsh}
% textutil -convert txt word.docx -output word.txt
```

標準入力、標準出力を使うこともできる。

```{zsh}
% cat word.docx | textutil -convert txt -stdin -stdout > word.txt
```

pdfをテキストファイルに変換する方法としては、pdftotextなどがある。pdftotextはpopplerに含まれるので、まずbrewでpopplerをインストールする。インストールにcommand line toolsが必要なので、まだインストールしていなければxcode-selectでインストールする。

```{zsh}
% xcode-select --install
% brew install poppler
```

pdftotextで変換する。精度はあまりよくないらしいので、専用のソフトウェアを使った方がいいかも知れない。

```{zsh}
% pdftotext adobe.pdf
```

## エンコーディングを変換する

nkfを使う。Macに最初から入ってはいないので、brewでインストールする。

```{zsh}
% brew install nkf
```

sjis_crlf.txtをUTF-8/LFに変換してutf8_lf.txtという名前で保存する場合は次のようにする。デフォルトでは半角カナは全角カナに変換される。

```{zsh}
% nkf -w -Lu sjis_crlf.txt > utf8_lf.txt
```

主なオプションは以下の通り。

|オプション|説明|
|---|---|
|-s, -e, -j, -w|Shift_JIS、EUC-JP、ISO-2022-JP、UTF-8に変換する。|
|-S, -E, -J, -W|元ファイルをShift_JIS、EUC-JP、ISO-2022-JP、UTF-8とみなす(無指定だと自動判別)|
|-Lu, -Lw, -Lm|改行文字をLF、CRLF、CRに変換する。|
|-X, -x|片仮名を全角、半角に変換する(無指定だと全角に変換)|
|-Z|英数字や一部の記号を半角にする。全角にするオプションはないっぽい。|
|--hiragana, --katakana|平仮名、片仮名に変換する。|
|--overwrite|変換結果で元ファイルを上書きする。|
|-g, --guess|変換せず、自動判別の結果を表示する。|

Macに最初から入っているエンコーディング変換コマンドとしてはiconvがある。元ファイルの文字コードの自動判別や改行文字の変換などの機能はないようなので、nkfの方が使いやすいと思う。

## 半角を全角にする

適当なコマンドが見当たらないのでrubyを使う。rubyはMacに最初から入っていると思うが、最新のバージョンを使いたければbrewなりrbenvなりでインストールする。mojiモジュールを使うのでgemでインストールする。

```{zsh}
% sudo gem install moji
```

ちょっと長いが、次のようにする。

```{zsh}
% cat utf8_lf.txt | ruby -r moji -nle 'puts Moji.han_to_zen($_)' > utf8_lf_zenkaku.txt
```

UTF-8以外のテキストファイルの場合は、nkfなどでUTF-8に変換してからrubyに流し込む。

```{zsh}
% cat sjis_crlf.txt | nkf -w | ruby -r moji -nle 'puts Moji.han_to_zen($_)' > utf8_lf_zenkaku.txt
```


## 重複しているファイルを探す

fdupesやrdfindなどのコマンドがある。どちらもbrewでインストールする。

```{zsh}
% brew install fdupes rdfind
```

fdupesの例。指定したフォルダにあるファイルをチェックする。-rをつけると子フォルダも再帰的に探す。.は現在のフォルダを意味する。

```{zsh}
 % fdupes -r .
./utf8_lf.txt
./utf8_lf_copy.txt
```

重複したファイルを削除するときは-dオプションをつける。重複ファイルの一覧が出るので、番号を入力して残すファイルと削除するファイルを選択し、pruneと入力するとファイルを削除する。exitでプログラムを終了する。-dに加えて-Nをつけると、ファイルの手動選択を省略して最初に見つかったファイル以外を削除する。