كيف يمكنك تطبيق أنماط نمط النمل في بيثون لتحديد مجموعات من الملفات؟

StackOverflow https://stackoverflow.com/questions/161755

  •  03-07-2019
  •  | 
  •  

سؤال

لدى Ant طريقة رائعة لتحديد مجموعات من الملفات، والأكثر سهولة هو استخدام ** للإشارة إلى شجرة الدليل.على سبيل المثال

**/CVS/*            # All files immediately under a CVS directory.
mydir/mysubdir/**   # All files recursively under mysubdir

يمكن رؤية المزيد من الأمثلة هنا:

http://ant.apache.org/manual/dirtasks.html

كيف يمكنك تنفيذ ذلك في بيثون، بحيث يمكنك القيام بشيء مثل:

files = get_files("**/CVS/*")
for file in files:
    print file

=>
CVS/Repository
mydir/mysubdir/CVS/Entries
mydir/mysubdir/foo/bar/CVS/Entries
هل كانت مفيدة؟

المحلول

بمجرد أن تصادف أ **, ، سيتعين عليك التكرار عبر بنية الدليل بأكملها، لذلك أعتقد في هذه المرحلة أن أسهل طريقة هي التكرار عبر الدليل باستخدام os.walk، وإنشاء مسار، ثم التحقق مما إذا كان يطابق النمط.ربما يمكنك التحويل إلى regex بشيء مثل:

def glob_to_regex(pat, dirsep=os.sep):
    dirsep = re.escape(dirsep)
    print re.escape(pat)
    regex = (re.escape(pat).replace("\\*\\*"+dirsep,".*")
                           .replace("\\*\\*",".*")
                           .replace("\\*","[^%s]*" % dirsep)
                           .replace("\\?","[^%s]" % dirsep))
    return re.compile(regex+"$")

(على الرغم من ملاحظة أن هذا ليس مميزًا بالكامل - فهو لا يدعم [a-z] أنماط النمط العالمية على سبيل المثال، على الرغم من إمكانية إضافة هذا على الأرجح).(الأول \*\*/ المباراة هي لتغطية حالات مثل \*\*/CVS مطابقة ./CVS, ، فضلا عن وجود فقط \*\* لتتناسب مع الذيل.)

ومع ذلك، من الواضح أنك لا ترغب في تكرار كل شيء أسفل الدليل الحالي عند عدم معالجة ملف ** النمط، لذلك أعتقد أنك سوف تحتاج إلى نهج من مرحلتين.لم أحاول تنفيذ ما يلي، وربما تكون هناك بعض الحالات الأساسية، ولكن أعتقد أنها يجب أن تنجح:

  1. قم بتقسيم النمط على فاصل الدليل الخاص بك.أي pat.split('/') -> ['**','CVS','*']

  2. كرر من خلال الدلائل، وانظر إلى الجزء ذي الصلة من النمط لهذا المستوى.أي. n levels deep -> look at pat[n].

  3. لو pat[n] == '**' قم بالتبديل إلى الإستراتيجية المذكورة أعلاه:

    • إعادة بناء النمط باستخدام dirsep.join(pat[n:])
    • تحويل إلى regex مع glob\_to\_regex()
    • بشكل متكرر os.walk من خلال الدليل الحالي، وبناء المسار بالنسبة إلى المستوى الذي بدأت منه.إذا كان المسار يطابق التعبير العادي، فاستسلم له.
  4. إذا لم يتطابق بات "**", ، وهو العنصر الأخير في النمط، ثم يؤدي إلى مطابقة جميع الملفات/الأديرة glob.glob(os.path.join(curpath,pat[n]))

  5. إذا لم يتطابق بات "**", ، وهو ليس العنصر الأخير في النمط، ثم لكل دليل، تحقق مما إذا كان مطابقًا (مع الكرة الأرضية) pat[n].إذا كان الأمر كذلك، كرر من خلاله، مع زيادة العمق (هكذا سوف ننظر إلى pat[n+1])

نصائح أخرى

وos.walk هو صديقك. نظرة على سبيل المثال في دليل بيثون ( https://docs.python.org/2/library/os هتمل # os.walk ) ومحاولة لبناء شيء من ذلك.

لتتناسب مع "**/CVS/*" مقابل اسم ملف تحصل عليه، يمكنك أن تفعل شيئا من هذا القبيل:

def match(pattern, filename):
    if pattern.startswith("**"):
        return fnmatch.fnmatch(file, pattern[1:])
    else:
        return fnmatch.fnmatch(file, pattern)

في fnmatch.fnmatch، "*" مباريات أي شيء (بما في ذلك خطوط مائلة).

وهناك التنفيذ في بناء التعليمات البرمجية المصدر نظام "WAF '. http://code.google كوم / ع / WAF / المصدر / استعراض / جذع / waflib / Node.py؟ ص = 10755 # 471 قد يكون هذا ينبغي أن تكون ملفوفة في مكتبة خاصة به؟

نعم. أفضل رهان هو، كما سبق أن اقترح، للعمل مع "os.walk. أو إرسال مغلفة حول ' غلوب ' و '<لأ href = "HTTP: / /docs.python.org/library/fnmatch.html "يختلط =" نوفولو noreferrer "> وحدات fnmatch ، ربما.

os.walk هو أفضل رهان لهذا. فعلت المثال التالي مع .svn لأنه كان ذلك في متناول يدي، وأنها عملت كبيرة:

import re

for (dirpath, dirnames, filenames) in os.walk("."):
    if re.search(r'\.svn$', dirpath):
        for file in filenames:
            print file
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top