簡體   English   中英

你如何在python中實現ant樣式模式集來選擇文件組?

[英]How would you implement ant-style patternsets in python to select groups of files?

Ant有一種很好的方法來選擇文件組,最方便的是使用**來表示目錄樹。 例如

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

這里可以看到更多的例子:

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

你將如何在python中實現這一點,以便你可以做類似的事情:

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

=>
CVS/Repository
mydir/mysubdir/CVS/Entries
mydir/mysubdir/foo/bar/CVS/Entries

對不起,這是你的OP后很長一段時間。 我剛剛發布了一個Python軟件包,它正是這樣做的 - 它叫做Formic,它可以在PyPI Cheeseshop上找到 使用Formic,您的問題可通過以下方式解決:

import formic
fileset = formic.FileSet(include="**/CVS/*", default_excludes=False)
for file_name in fileset.qualified_files():
    print file_name

有一個輕微的復雜性:default_excludes。 Formic,就像Ant一樣,默認情況下排除CVS目錄(因為大多數情況下從構建文件中收集文件是危險的),問題的默認答案將導致沒有文件。 設置default_excludes = False會禁用此行為。

一旦遇到** ,你將不得不在整個目錄結構中進行遞歸,所以我認為在這一點上,最簡單的方法是使用os.walk遍歷目錄,構建一個路徑,然后檢查它是否與模式匹配。 您可以通過以下方式轉換為正則表達式:

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+"$")

(雖然注意到這不是那么全功能 - 但它不支持[az]樣式的glob模式,盡管可能會添加它)。 (第一個\\*\\*/匹配是為了覆蓋像\\*\\*/CVS匹配./CVS ,以及只有\\*\\*來匹配尾部。)

但是,顯然你不想在不處理**模式時通過當前目錄下的所有內容進行遞歸,所以我認為你需要一個兩階段的方法。 我沒有嘗試過實現下面的內容,並且可能有一些極端情況,但我認為應該可行:

  1. 拆分目錄分隔符上的模式。 pat.split('/') -> ['**','CVS','*']

  2. 通過目錄進行遞歸,並查看此級別的模式的相關部分。 即。 n levels deep -> look at pat[n]

  3. 如果pat[n] == '**'切換到上述策略:

    • 使用dirsep.join(pat[n:])重構模式dirsep.join(pat[n:])
    • 使用glob\\_to\\_regex()轉換為正則表達式
    • 遞歸os.walk通過當前目錄,建立相對於您開始的級別的路徑。 如果路徑與正則表達式匹配,則將其生成。
  4. 如果pat與"**"不匹配,並且它是模式中的最后一個元素,那么產生匹配glob.glob(os.path.join(curpath,pat[n]))所有文件/目錄glob.glob(os.path.join(curpath,pat[n]))

  5. 如果pat與"**"不匹配,並且它不是模式中的最后一個元素,那么對於每個目錄,檢查它是否匹配(使用glob) pat[n] 如果是這樣,通過它遞減,增加深度(所以它將看pat[n+1]

os.walk是你的朋友。 查看Python手冊( https://docs.python.org/2/library/os.html#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.com/p/waf/source/browse/trunk/waflib/Node.py?r=10755#471可能這應該包含在自己的庫中嗎?

對。 正如已經建議的那樣,你最好的選擇是使用'os.walk'。 或者,也許是圍繞' glob '和' 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 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM