LoginSignup
46
44

More than 5 years have passed since last update.

『Macで日本語ファイルをgitにコミットするのやめて><』とりあずMacとLinuxで互換性のない日本語ファイルを探すスクリプト書いた

Last updated at Posted at 2013-07-11

最近携わっているPHPのプロジェクトでは、プログラムを日本語で書いています。クラス名・変数名はもちろんファイル名も日本語です。(なぜ日本語で書くことにしたのか、そこらへんのモチベーションについては別記事にまとめたい)

このプロジェクトは開発環境がMac、プロダクション環境がLinuxなのですが、日本語ファイル名のPHPがオートロードされないなどの問題が発生しました。しらべたところ、MacのファイルシステムとLinuxのファイルシステムでUnicodeの規格が違うのが原因でした。詳しくは、「紹介マニアどらふと版: Mac OS X におけるファイル名に関するメモ(NFC, NFD等)」の記事が参考になります。

簡単にファイルシステムの違いを説明すると、

Mac: NFDという規格。濁点半濁点などバラしている(正規化)。「だ」は「た」「゛」の6バイトになる
Linux: NFCという規格。濁点半濁点をバラさない(非正規化)。「だ」は3バイトになる

という違いがあります。

Macで作ったNFDのファイルをgitにcommitすると、そのまま正規化された状態でステージされます。それを、Linuxでgit pullしたときに、NFDからNFCに変換してくれればいいのですが、NFDのままファイルが作られます。PHPのソースコードはNFCですから、ファイル名が決め打ちで参照されていると、「Macでは動いていたけど、Linuxで動かなくなった」という現象が発生するのです。

日本語ファイルをコミットされてしまったのはしょうがないので、ひとまず問題のあるファイルを洗い出すために、NFDのファイルを根こそぎ探しだすスクリプトをPythonで作りました。

使い方

$ find-nfd -h
usage: find-nfd [-h] [path]

Find NFD files

positional arguments:
  path        path to find(Default: current working directory)

optional arguments:
  -h, --help  show this help message and exit

ソースコード

find-nfd.py
#!/usr/bin/env python
import os
import argparse
from unicodedata import normalize

def fild_all_files(directory):
    for root, dirs, files in os.walk(directory):
        yield root
        for file in files:
            yield os.path.join(root, file)

def to_nfc(string):
    string = string.decode("utf8")
    string = normalize("NFC", string)
    string = string.encode("utf8")
    return string

def is_nfd(string):
    if to_nfc(string) == string:
        return False
    else:
        return True

def find_nfd_files(directory):
    for file in fild_all_files(directory):
        if is_nfd(file):
            yield file

def main():
    parser = argparse.ArgumentParser(description="Find NFD files")
    parser.add_argument("path", type=str, help="path to find(Default: current working directory)", nargs='?', default=os.getcwd())
    args = parser.parse_args()

    count = 0

    for file in find_nfd_files(args.path):
        print file
        count += 1

    print ""
    print "%u files found" % (count)

if __name__ == "__main__":
    main()

使ってみる

Macで作ったファイルです↓

$ php -r 'var_dump(glob("/tmp/test/1/*"));'
array(7) {
  [0] =>
  string(13) "/tmp/test/1/a"
  [1] =>
  string(13) "/tmp/test/1/b"
  [2] =>
  string(17) "/tmp/test/1/schon"
  [3] =>
  string(19) "/tmp/test/1/schön"
  [4] =>
  string(30) "/tmp/test/1/한글"
  [5] =>
  string(27) "/tmp/test/1/はひふへほ"
  [6] =>
  string(42) "/tmp/test/1/ぱぴぷぺぽ"
}

見た目はNFDなのかNFCなのか全く区別がつきませんが、「はひふへほ」と「ぱぴぷぺぽ」でstringのバイト数が違うのがわかります。
ドイツ語のウムラウトや、韓国語のハングルもNFDになっているのが分かります。

この中から、NFDのファイルを探してみます:

$ find-nfd.py /tmp/test/1
/tmp/test/1/schön
/tmp/test/1/한글
/tmp/test/1/ぱぴぷぺぽ

3 files found

3つ見つかりました。

こういうファイルを見つけたら、Linux環境かWindows環境でリネームして、gitに入れなおすことになります。

「こんなめんどくさいこと毎回やるのか?」と言われそうですが、vagrantでDebian環境がたった5分でできあがるように開発の仕組み自体を変えています:)

Macとは言え、プロダクション環境ではないので、無駄なハマリを回避するには、プロダクション環境と全く同じ開発環境を作ることが大事ですね。

46
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
44