2

Can python generate path with multi-sub-paths by short form syntax like this ?

vars=project/{DEBIAN,usr/{bin,usr/{applications,icons,share}},computer}
Sanjay T. Sharma
  • 22,857
  • 4
  • 59
  • 71
UhBaUnTaUh
  • 37
  • 7

3 Answers3

1

No, there is no such built-in shorthand. A reasonably pythonic way would be:

vars = ["project" + path for path in (
    ["/DEBIAN"] +
    ["/usr" + path for path in (
        ['/bin'] +
        ['/usr' +  path for path in [
            "/applications",
            "/icons",
            "/share"]
        ]
    )] +
    ['/computer']
)]

EDIT:

You can define a function to make this easier. Here's a lazy generator version:

def expand(base, paths):
    for path in paths:
        if type(path) == str:
            yield base + path
        else:
            for p in path:
                yield base + p

vars = expand("project", [
    "/debian",
    expand("/usr", [
        "/bin",
        expand("/usr", [
            "/applications",
            "/icons",
            "/share"
        ]),
        "/computer"
    ])
])
Community
  • 1
  • 1
Eric
  • 95,302
  • 53
  • 242
  • 374
  • You could go for a string-parsing approach if you wanted. I think this is the best way to do it in a single statement – Eric Oct 20 '12 at 23:44
1

Normally I would have suggested to use something like

def extend(base, *others):
    [base + o for o in others] if others else [base]

and then do

 extend("project", "/debian", *extend("/usr", *(extend("/bin") + extend("/usr", "/applications", "/icons", "/share"))))

. But as you prefer parsing a string, I try to provide an alternative:

def commasplit(s):
    start = 0
    level = 0
    for i, c in enumerate(s):
        if c == '{':
            level += 1
        elif c == '}':
            level -= 1
        elif c == ',' and level == 0:
            yield s[start:i]
            start = i+1
    yield s[start:]

def split(s):
    import re
    found = False
    for m in re.finditer("(\{.*\})",s):
        found = True
        for p in commasplit(s[m.start() + 1:m.end() - 1]):
            for i in split(p):
                yield s[:m.start()] + i + s[m.end():]
    if not found:
        yield s

cs = "a,b,c,{d,e,f},g"
print list(commasplit(cs)) # -> seems to work

s = "project/{DEBIAN,usr/{bin,usr/{applications,icons,share}},computer}"
print s
for n, i in enumerate(split(s)): print n, i # ->  as well.
glglgl
  • 89,107
  • 13
  • 149
  • 217
  • >>> print list(commasplit(cs)) # -> seems to work ['a', 'b', 'c', **'{d,e,f}'**, 'g'] – UhBaUnTaUh Oct 21 '12 at 08:06
  • 1
    @UhBaUnTaUh That is right. It is deliberately intended to work on the 1st level only. `split()` calls itself recursively, so in the end everything should be right. – glglgl Oct 21 '12 at 08:21
  • You make me known more about yield and enumerate, I was became familiar normal return that make me had some awful programming habit. Also, your code make me recall about interpreter/compiler programming. Thank you. – UhBaUnTaUh Oct 21 '12 at 10:16
  • Excuse me, I'm a newer in this coding style. I tried to read your code to modify it to my wanted way, however I didn't understand about iter concept, so I don't know how to modify it. May you help me more to modify your code to this style ? pythonGenPath ("project,[DEBIAN,usr,[bin,usr,[applications,icons,share/winpath]],computer]") – UhBaUnTaUh Oct 21 '12 at 10:41
  • I think it will be useful way to create list without double quote. I wana modify it to generate multidimension double-quote-less string list. – UhBaUnTaUh Oct 21 '12 at 10:52
  • @UhBaUnTaUh I am not sure about this syntax - what is the rule when a `,` becomes a `/` and when not? – glglgl Oct 21 '12 at 19:26
  • I'm sorry for mistake described. I refer to string list without quote like the eval-using dummy, that I had written : easy ("project,[DEBIAN,usr,[bin,usr,[applications,icons,share/winpath]],computer]")# Result ["project",["DEBIAN","usr",["bin","usr",["applications","icons","share/winpath"]],"computer"]] – UhBaUnTaUh Oct 21 '12 at 21:13
0

Thank you.

I try to write my code.

I always use ["0,1,2,3,4,5,6,7,8,9".split(","),["a,b,c,d,e".split(",")]] instead of nomal list.

Because it's faster--without shift press, clearly, and make sense more than ["x","y","z"].

So, I hope there will be some string method can act like bash, below code, in python, soon...

Python syntax : project,[DEBIAN,usr,[bin,usr,[applications,icons,share/winpath]],computer]

Bash syntax : project/{DEBIAN,usr/{bin,usr/{applications,icons,share}},computer}

import re
def genpaths (multils, root=""):
    suc=[]
    for l in multils:
        if type(l) == type([]):
            suc.extend(genpaths (l, root+multils[multils.index(l)-1]+"/"))
        else: 
            suc.append( root+l)
    return filter(None, suc)

def easylist (s):
    s=eval("['''"+re.sub("(\]+)(''',''')?", "'''\\1,'''",re.sub("(''',''')?(\[+)","''',\\2'''",re.sub(",","''','''",s)))+"''']")
    return s

def bashlist (s):
    s=eval("['''"+re.sub("(\}+)(''',''')?", "'''\\1,'''",re.sub("(/)?(\{+)","''',\\2'''",re.sub(",","''','''",s))).replace("{","[").replace("}","]")+"''']")
    return s

def pythonGenPath (s):
    return genpaths(bashlist (s))

def bashGenPath (s):
    return genpaths(bashlist (s))

#testing
print pythonGenPath ("project,[DEBIAN,usr,[bin,usr,[applications,icons,share/winpath]],computer]")
print bashGenPath ("project/{DEBIAN,usr/{bin,usr/{applications,icons,share}},computer}")

Result is :

['project', 'project/DEBIAN', 'project/usr', 'project/usr/bin', 'project/usr/usr', 'project/usr/usr/applications', 'project/usr/usr/icons', 'project/usr/usr/share', 'project/computer']
UhBaUnTaUh
  • 37
  • 7
  • 1
    Your code is very smelly because it uses `eval()` for no reason. I try to improve it... – glglgl Oct 21 '12 at 06:56
  • ^.^ I 'm, sorry. I'm lazy to define loop and function and my programming knowledge is terrible as a like as my english skill. I just use this code to build my debian package project. However, I hope someone will give us more higher pretty code. Thank you. ;D – UhBaUnTaUh Oct 21 '12 at 07:33