shell python glob中的大括号扩展

xu3bshqb  于 2023-03-13  发布在  Shell
关注(0)|答案(6)|浏览(194)

我有python 2.7,并尝试发出:

glob('{faint,bright*}/{science,calib}/chip?/')

我没有获得匹配项,但是从shell echo {faint,bright*}/{science,calib}/chip?中得到:

faint/science/chip1 faint/science/chip2 faint/calib/chip1 faint/calib/chip2 bright1/science/chip1 bright1/science/chip2 bright1w/science/chip1 bright1w/science/chip2 bright2/science/chip1 bright2/science/chip2 bright2w/science/chip1 bright2w/science/chip2 bright1/calib/chip1 bright1/calib/chip2 bright1w/calib/chip1 bright1w/calib/chip2 bright2/calib/chip1 bright2/calib/chip2 bright2w/calib/chip1 bright2w/calib/chip2

我的表情怎么了?

8ehkhllq

8ehkhllq1#

将滴注与大括号扩展结合使用。

pip install braceexpand

样品:
x一个一个一个一个x一个一个二个x

6yt4nkrj

6yt4nkrj2#

{..}称为大括号扩展,它是在发生全局绑定之前应用的单独步骤。
它不是glob的一部分,也不受python glob函数的支持。

20jt8wwn

20jt8wwn3#

由于Python中的glob()不支持{},因此您可能需要类似于

import os
import re

...

match_dir = re.compile('(faint|bright.*)/(science|calib)(/chip)?')
for dirpath, dirnames, filenames in os.walk("/your/top/dir")
    if match_dir.search(dirpath):
        do_whatever_with_files(dirpath, files)
        # OR
        do_whatever_with_subdirs(dirpath, dirnames)
yvfmudvl

yvfmudvl4#

that other guypointed out一样,Python不直接支持大括号扩展,但是由于大括号扩展是在通配符求值之前完成的,所以你可以自己完成,例如:

result = glob('{faint,bright*}/{science,calib}/chip?/')

变成

result = [
    f 
    for b in ['faint', 'bright*'] 
    for s in ['science', 'calib'] 
    for f in glob('{b}/{s}/chip?/'.format(b=b, s=s))
]
9udxz4iz

9udxz4iz5#

如其他答案所述,大括号扩展是glob的预处理步骤:展开所有的大括号,然后对每个结果运行glob(大括号展开将一个字符串变成一个字符串列表)。
Orwellophile推荐braceexpand库,我觉得这个问题太小了,不值得依赖(尽管这是一个常见的问题,应该放在标准库中,最好打包在glob模块中)。
这里有一种方法,只需要几行代码就可以做到。

import itertools
import re

def expand_braces(text, seen=None):
    if seen is None:
        seen = set()

    spans = [m.span() for m in re.finditer("\{[^\{\}]*\}", text)][::-1]
    alts = [text[start + 1 : stop - 1].split(",") for start, stop in spans]

    if len(spans) == 0:
        if text not in seen:
            yield text
        seen.add(text)

    else:
        for combo in itertools.product(*alts):
            replaced = list(text)
            for (start, stop), replacement in zip(spans, combo):
                replaced[start:stop] = replacement

            yield from expand_braces("".join(replaced), seen)

### testing

text_to_expand = "{{pine,}apples,oranges} are {tasty,disgusting} to m{}e }{"

for result in expand_braces(text_to_expand):
    print(result)

印刷品

pineapples are tasty to me }{
oranges are tasty to me }{
apples are tasty to me }{
pineapples are disgusting to me }{
oranges are disgusting to me }{
apples are disgusting to me }{

现在的情况是:
1.嵌套括号可能产生非唯一的结果,因此我们使用seen只产生尚未看到的结果。

  1. spanstext中所有最里面的平衡括号的起始索引和终止索引。[::-1]切片颠倒了顺序,使索引从最高到最低(稍后将讨论)。
  2. alts的每个元素都是对应的逗号分隔的替代项列表。
    1.如果没有任何匹配(text不包含对称括号),则生成text本身,确保它对于seen是唯一的。
    1.否则,使用itertools.product迭代逗号分隔的备选项的笛卡尔积。
    1.用当前替换项替换花括号中的文本。因为我们要就地替换数据,所以它必须是一个可变序列(list,而不是str),并且我们必须首先替换最高的索引。如果我们首先替换最低的索引,后面的索引可能会与spans中的索引不同。这就是为什么我们在spans最初创建时将其反转。
  3. text可能在花括号中有花括号。正则表达式只找到不包含任何其他花括号的平衡花括号,但嵌套花括号是法律的的。因此,我们需要递归,直到没有嵌套花括号为止(len(spans) == 0的情况)。Python生成器递归使用yield from重新生成递归调用的每个结果。
    在输出中,{{pine,}apples,oranges}首先被展开为{pineapples,oranges}{apples,oranges},然后每个{pineapples,oranges}{apples,oranges}都被展开。如果我们不使用seen请求唯一结果,oranges结果将出现两次。
    m{}e中的空括号扩展为空,因此这只是me
    不对称括号(如}{)保持原样。
    如果需要为大型数据集提供高性能,则不应使用此算法,但它是大小合理的数据的通用解决方案。
igsr9ssn

igsr9ssn6#

wcmatch库有一个类似于Python的标准glob的接口,它有一些选项来启用大括号扩展、波浪线扩展等等。

from wcmatch import glob

glob.glob('{faint,bright*}/{science,calib}/chip?/', flags=glob.BRACE)

相关问题