Python
maya

【MAYA】あるファイル名に似た名前のファイル一覧を同じフォルダから探す

同じフォルダから名前が似たファイルを探す処理が必要になったので、difflibモジュールとやらを使って、ざざっとクラスにしてみた。動作確認までして思ったけど、mayaが関係ない処理だった。
とはいえ、MAYA上で動作確認してるし、この後の記事で登場するかもしれないので、mayaの記事と言うことにしておく。

MAYA 2018 + MacOS Sierra および、 MAYA 2017 + Windows10 Pro で動作確認しました。

作成したクラス

import os
import difflib

class SimilarFilenameFinder(object):
    """
    あるファイル名に似た名前のファイル一覧を同じフォルダから探す
    """

    def __init__(self, threshold=0.0):
        """
        :param threshold: 敷居類似度 ここより低い類似度は結果としない
        :type threshold: float
        """
        super(SimilarFilenameFinder, self).__init__()
        self.threshold = threshold
        self._matcher = difflib.SequenceMatcher()

    def find_in_same_folder(self, base_file_name, folder_path=None):
        """
        あるファイル名に似た名前のファイル一覧を同じフォルダから探す

        :param base_file_name: 対象フォルダ(未指定でファイルと同じ階層)
        :type base_file_name: str
        :param folder_path: 探索ファイルパス(もしくは名前のみ)
        :type folder_path: str
        :return: ファイル一覧 と 類似度一覧 (indexが同じもので紐付けて使う)
        :rtype: lisr of str, and list of float
        """
        similar_files_info = []
        if folder_path is None:
            folder_path = os.path.dirname(base_file_name)
        if not os.path.isdir(folder_path):
            # フォルダが取得できないのでNoneを返す
            return None, None
        if not os.path.isfile(base_file_name):
            # ファイル名ではないのでNoneを返す
            return None, None
        files = os.listdir(folder_path)
        self._matcher.set_seq1(os.path.basename(base_file_name))
        for f in files:
            if os.path.join(folder_path , f) == base_file_name:
                # 自分との比較は省く
                continue
            file_name = os.path.basename(f)
            self._matcher.set_seq2(file_name)
            similar_ratio = self._matcher.ratio()
            if similar_ratio >= self.threshold:
                similar_files_info.append({'name': file_name, 'ratio': similar_ratio})
        similar_files_info.sort(key=lambda x: 1.0 - x['ratio'])
        return [x['name'] for x in similar_files_info], [x['ratio'] for x in similar_files_info]

使い方の例

類似度が高い順で、周りのファイル名一覧が帰ってきます。

sf = SimilarFilenameFinder(0.1)
found_files, ratios = sf.find_in_same_folder(
        '/git/hogehoge/README.md') # ファイルパスを指定する
if found_files is not None:
    for i, _ in enumerate(found_files):
        print(found_files[i], ratios[i])

# 以下、出力例
#('LICENSE.md', 0.5263157894736842)
#('BUILD.md', 0.47058823529411764)
#('.idea', 0.2857142857142857)
#('img', 0.16666666666666666)
#('.git', 0.15384615384615385)
#('Gemfile', 0.125)
#('Rakefile', 0.11764705882352941)
#('.DS_Store', 0.1111111111111111)
#('.gitignore', 0.10526315789473684)