読者です 読者をやめる 読者になる 読者になる

HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

ファイルにASCII文字以外が含まれているかを判定するスクリプト

PHP

唐突に、(例外はあるが、EUC-JP、Shift_JISISO-2022-JPUTF-8あたりを対象としたときに)文字エンコーディングを気にしなくてよいファイルかどうかを判定したくなって、ちょっとしたユーティリティを作ってみたらしい。

<?php
class StringUtil {
    /**
     * いわゆるテキストファイルに出現するシングルバイト文字を
     * 検出するためのパターン。
     */
    private static $patterns = array(
        '/[a-zA-Z0-9!"#$%&()=~^|@`:*;+{}]/',
        '/[- ,.<>?_[\]\/\\\\]/',
        "/['\r\n\t\v\f]/",
    );
    /**
     * シングルバイト文字のみを含む文字列かどうかを判定する。
     *
     * @param string $str 判定する文字列
     * @return bool true:  シングルバイト文字のみを含む
     *              false: シングルバイト文字以外を含む
     */
    public static function containsOnlySingleByteChars($str) {
        $str = preg_replace(self::$patterns, '', $str);
        return (strlen($str) === 0);
    }
}

パターンの中には、図形文字(0x21〜0x7e)と空白(0x20)、および制御文字の一部(HT、NL(LF)、VT、NP、CR)を含む。(ASCII文字コード : IT用語辞典)
(VTとNPはどうしようかと思ったが、一応入れておいた)
(BELとBSは、どうしようかと思ったが、はずしておいた)

ちなみに、エスケープシーケンスとして、以下が使用可能、というのは余談。

PHP HT(\t) NL(\n) VT(\v) NP(\f) CR(\r)
Java BS(\b) HT(\t) NL(\n) NP(\f) CR(\r)
C/C++ BEL(\a) BS(\b) HT(\t) NL(\n) VT(\v) NP(\f) CR(\r)

いわゆる「ASCII文字だけかどうか」の判定だが、制御文字のほとんどは入れていない。それの一番大きな理由は、ISO-2022-JP(俗に言うJISコード)でエンコードされたファイルがASCII文字のみと判定されないようにするため。パターンを判定するのも面倒だし、ということで。まぁ、「ふつーのテキストファイル」なら大丈夫でしょう。

で、これを使用したサンプル。

<?php
require_once('./StringUtil.php');

array_shift($argv);

foreach ($argv as $file) {
    if (!is_readable($file)) {
        printf("Warning: %s: cannot read.\n", $file);
        continue;
    }

    $contents = file_get_contents($file);

    if (StringUtil::containsOnlySingleByteChars($contents)) {
        printf("O: %s\n", $file);
    } else {
        printf("X: %s\n", $file);
    }
}