1. トップ
  2. 新着ニュース
  3. IT
  4. IT総合

Windowsにおける改行文字の扱い

ASCII.jp / 2023年5月21日 10時0分

 コンピュータの世界で「テキストファイル」と呼ばれるファイルは存在するが、実際にテキストファイルをテキストファイルならしめているのは、ファイル自体ではなく、それを読み込むプログラムのほうである。

Windows 10/11の「メモ帳」アプリでは、文字コードや改行コードもWindowsの標準以外のものに対応していて、ステータスバーに表示する機能がある

 より簡単に言えば、中身がテキストであるという前提に立ってファイルを読み込んで解釈するプログラムは存在するが、読み込むファイル自体には、テキストファイルという特別な区別は存在せず、ファイルは等しく同じものしかない。

 このテキストファイルには「行末文字」がある。改行文字、改行コードともいう。本記事では「ラインフィード」が「改行」となり、混乱を防ぐ意味からも、テキストの行末にある区切り文字を「行末文字」と呼ぶことにする。

 行末文字は、短いテキストファイルには存在しないこともあるが、行末文字があるために、テキストファイルには「行」が存在できる。行末文字は主にプラットフォームで決まっており、「LFのみ」「CRのみ」「CRLF」の3パターンがある。

 現在では、テキストファイルをインターネットから入手することもあり、必ずしもプラットフォームと同じ行末文字が使われているとは限らない。

 Windowsでは、MS-DOS時代からテキストの行末文字は「CRLF」だった。MS-DOSは、先行する8ビットCPU用OS「CP/M」と互換性を持たせたからだ。このあたりについては、過去記事(「Windows 10 RS5では「メモ帳」がCR+LF以外の行末記号に対応」)も参照してほしい。

行末文字とテキストファイル

 テキストファイルは、テキストと行末文字やタブ文字などの制御コードなどからなるファイルだが、一般にファイルとして、テキストファイルではないものと比較して何か特別なしるしがあるわけではない。

 拡張子に「txt」を用いることも多いが、これもあくまでも「約束事」の範囲を出ない。たとえば、拡張子をほかのものにすることもできれば、拡張子が「txt」なのにバイナリ形式になっていることだってある。Windowsの拡張子は、デフォルトで扱うプログラムとの対応に使われているだけで、ファイル形式に関しては、何も保証されていないことは理解しておいたほうがいいだろう。

 そもそも、ファイルのすべてのコードを判定して、テキストファイルかどうかを判定することも難しい。どんなに巨大でも、ファイルを全部見なければ、テキストかどうかわからないため、判定に時間がかかってしまう。また、文字コードにより、使われるコード範囲が異なるため、文字コードを特定しないと、ファイル内容がテキストかどうかの判定ができない。しかし、一般的にファイルは文字コードに関する情報を持たず、「Windows XPでは、シフトJISコードを使う」といった約束事で対応していることがほとんどだからだ。

 文字コードにより、絶対に登場しないバイト列は存在するが、その文字がファイル中に存在しないのでなければ、判定できない。また、文字コード同士、たとえば「ASCII」と「UTF-8」のようにバイト列が共通している場合があり、共通部分の文字しか入っていない場合には、コードを決定できない。

 文字コードが確定していなければ、ファイルがテキスト形式かどうかを判断できず、また、ファイルから文字コードを自動判定することは、常にできるわけではない。

 前述のようにテキストファイルの行末文字には、3つのパターンがある。実際には、これも約束事でしかなく、複数の行末文字が存在するようなファイルを作ることも可能だ。かつて、Windowsに付属のメモ帳は、Windows標準の「CRLF」しか許容していなかったが、Windows 10/11に付属するメモ帳では、複数の文字コード、複数の行末文字を許容している(冒頭画面)。判定は、最初の行の行末文字で判定されるようだが、行末文字が混在していても読み込むことが可能なのである

テキストモードとバイナリモード

 プログラムは、ファイルを処理する場合に外部記憶装置からメモリに読み込みをする。このとき、ファイル内容が「テキスト」であるとして、前処理をすることがあり、これを一般的に「テキストモード」という。

 逆に、テキストではない前提でファイルを読み込むことを「バイナリモード」という。ファイルを読み込むプログラムは、必ず、このモードのどちらか1つを持つ(両方持つプログラムも存在する)。ファイルシステムには、「テキストファイル」という区別を持つファイルは存在しないが、プログラムにはテキストモードとバイナリモードという区別がある。

 プログラムによっては、バイナリモードでの読み込みを強制する機能を持つ場合がある。たとえば、メモ帳のようなエディタプログラムは、テキストモードしか持たないが、Windowsの標準コマンドfc.exeには、「テキストモード」と「バイナリモード」の区別がある。

 テキストモードでは、行末文字が意味を持つ。読み込み中に行末文字を見つけたら、そこを行末として、テキストの行を構成していく。このときに行末文字は、内部コードに変換されることが多い。というのも前述のように3種類の行末文字があるからだ。

 今のところ、行末文字はこの3種に限定されるので、この処理は、人手を介さずに完全に自動で可能。行末文字が混在していても基本的には問題ない。かつては、プラットフォームの約束事にしか従わないプログラムもあったが、現在ではどの行末文字でも正しく文末として認識するような作りが一般的だ。

 かつては、プラットフォームでテキストファイルの行末文字に対して約束事があり、これに従ってプログラムが作られていた。たとえば、Windows 10より前、メモ帳はCRLFだけを行末文字として認識していたため、Unixなどから転送されてきたテキストファイルでは行が全部つながってしまったことがあった。

 こうしたこともあり、かつては、テキストファイルの行末文字を変換して処理する必要があったが、最近では行末文字の変換はほぼ不要となった。

PowerShellでのテキストモードとバイナリモード

 PowerShellのコマンドの中には、直接ファイルを読み込んで処理できるものが60個程度ある。これらは、基本的にはテキストモードを使う。たとえば、文字列検索のSelect-Stringコマンドは、テキストモードでファイルを読み込んで文字列検索をする。

 このコマンドに限らず、テキストモードで読み込まれたテキストファイルは、行末文字が内部コードに置き換わるので、検索などで行末文字を見つけることができないことが多い。この点には注意しないと、複数行にまたがるパターンを検索しようとしてうまくいかなくなることがある。

 正規表現エンジンにも、シングルラインモード、マルチラインモードといった動作モードがある。マルチラインモードでは、行末文字を認識して複数行のテキストとして検索をする。このため、行末文字自体を検索することはできず、代わりに文頭や文末を表わすアンカーを利用する。もちろん、行末文字は読み込み時に変換されてしまうので、行末文字を表わすエスケープ文字「 」などもヒットしない。

 これに対してシングルラインモードでは、行末文字も普通の文字のように扱われ、たとえば、任意の1文字を表わす「.」に行末文字がヒットするようになる。この場合、アンカーは検索対象の先頭と末尾にしか一致しなくなる。しかし、複数行にまたがるパターンを検索できるようになる。

 なお、Windowsでは、シングルラインモードのときの行末文字CRLFは、「 」と指定する必要がある。シングルラインモードでは、行末文字がどうなっているのかを理解しておく必要がある。

 前述のように、ファイルをテキストとして扱うかどうかは、プログラムの問題である。PowerShellのコマンドのほとんどは、ファイルをテキストモードで読み込む、このため、多くの場合は複数行にまたがる処理ができない。

 バイナリモードでファイルを扱いたい場合、Get-Contentコマンドに「-Raw」オプションを付けて読み込み、これをコマンドで処理する。こうして読み込まれたファイルなら、select-stringコマンドで行末文字を含む部分を探すこともできる。たとえば、行末文字を含むパターン「1 T」のようなパターンを検索したければ、

Get-Content -Raw <ファイルパス> | select-String '1 T

とする。

Get-Content -Rawオプションを使うと、バイナリモードでファイルが読み込まれ、改行文字がそのままの状態になる。このため、行末文字CR( )やLF( )を含めることで、複数行にわたる検索ができるようになる

 逆に「-Raw」オプションがなければ、Get-Contentコマンドは、ファイルをテキストモードで読み込み、パイプには分解された複数のテキスト行を送り出す。この場合、後続のSelect-Stringコマンドでは、これを1行1行個別に検索処理をするため、複数行にわたるパターンを検索することができず、行末文字も見つからない。

 行末文字を扱えるかどうかは、コマンド自体の問題である。ファイルを直接読み込めるPowerShellの大半のコマンドは、テキストモードで動作している。これを理解しないと、Select-Stringコマンドで直接ファイルを読み込んだとき、行末文字が見つからなくて悩むことになりかねない。バイナリモードでファイルを扱いたいならば、必ずGet-Contentコマンドで「-Raw」オプションを使う。

 テキストファイルと普通に呼んでいるため、世の中には「テキストファイル」という特別なファイルが存在するかのような気がしているが、実際には、テキストファイルは約束事でしかない。テキストファイルをテキストファイルとして成り立たせているのは、これを読み込むプログラムであるということは、きちんと理解しておいたほうがいいだろう。

この記事に関連するニュース

トピックスRSS

ランキング

記事ミッション中・・・

10秒滞在

記事にリアクションする

記事ミッション中・・・

10秒滞在

記事にリアクションする

デイリー: 参加する
ウィークリー: 参加する
マンスリー: 参加する
10秒滞在

記事にリアクションする

次の記事を探す

エラーが発生しました

ページを再読み込みして
ください