كيف يمكنك تطبيق أنماط نمط النمل في بيثون لتحديد مجموعات من الملفات؟
سؤال
لدى 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
, ، فضلا عن وجود فقط \*\*
لتتناسب مع الذيل.)
ومع ذلك، من الواضح أنك لا ترغب في تكرار كل شيء أسفل الدليل الحالي عند عدم معالجة ملف **
النمط، لذلك أعتقد أنك سوف تحتاج إلى نهج من مرحلتين.لم أحاول تنفيذ ما يلي، وربما تكون هناك بعض الحالات الأساسية، ولكن أعتقد أنها يجب أن تنجح:
قم بتقسيم النمط على فاصل الدليل الخاص بك.أي
pat.split('/') -> ['**','CVS','*']
كرر من خلال الدلائل، وانظر إلى الجزء ذي الصلة من النمط لهذا المستوى.أي.
n levels deep -> look at pat[n]
.لو
pat[n] == '**'
قم بالتبديل إلى الإستراتيجية المذكورة أعلاه:- إعادة بناء النمط باستخدام
dirsep.join(pat[n:])
- تحويل إلى regex مع
glob\_to\_regex()
- بشكل متكرر
os.walk
من خلال الدليل الحالي، وبناء المسار بالنسبة إلى المستوى الذي بدأت منه.إذا كان المسار يطابق التعبير العادي، فاستسلم له.
- إعادة بناء النمط باستخدام
إذا لم يتطابق بات
"**"
, ، وهو العنصر الأخير في النمط، ثم يؤدي إلى مطابقة جميع الملفات/الأديرةglob.glob(os.path.join(curpath,pat[n]))
إذا لم يتطابق بات
"**"
, ، وهو ليس العنصر الأخير في النمط، ثم لكل دليل، تحقق مما إذا كان مطابقًا (مع الكرة الأرضية)pat[n]
.إذا كان الأمر كذلك، كرر من خلاله، مع زيادة العمق (هكذا سوف ننظر إلىpat[n+1]
)
نصائح أخرى
عذرا، هذا وقتا طويلا بعد OP الخاص بك. لقد صدر للتو حزمة بايثون الذي يفعل ذلك بالضبط - أنه دعا الفورميك وأنها متاحة في PyPI Cheeseshop أ >. مع الفورميك، يتم حل مشكلتك مع:
import formic
fileset = formic.FileSet(include="**/CVS/*", default_excludes=False)
for file_name in fileset.qualified_files():
print file_name
وهناك واحد طفيف التعقيد: default_excludes. الفورميك، تماما مثل النملة، يستثني الدلائل CVS افتراضيا (كما بالنسبة للجزء الأكبر جمع الملفات منها لبناء خطير)، والجواب الافتراضي على سؤال من شأنه أن يؤدي إلى أية ملفات. وضع default_excludes = تعطيل كاذبة هذا السلوك.
و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