Finding folders back based on a predefined folder

2019-08-28 00:26发布

We've a dynamic folder structure syntax set up like:

:projectRoot:/dev/model/:parentHierarchy:/:assetName:/data/obj
:projectRoot:/dev/model/:parentHierarchy:/:assetName:/data/fbx
:projectRoot:/asset/shots/:parentHierarchy:/animation/:assetName:/scenes
:projectRoot:/asset/shots/:parentHierarchy:/rendering/:assetName:/scenes

Where the words between two colons ':' are variables. Now based on a single path I want to retrieve the projectRoot, parentHierarchy and assetName.

The projectRoot variable and parentHierarchy variable allow 1 or more folders to be present so it can hold subfolders. The assetName variable is restricted to a single folder. These are the defined as in my try seen below.

So let's say I pass in:

C:/Projects/foo/dev/model/props/furniture/couch/data/

This should return:

projectRoot = C:/Projects/foo/
parentHierarchy = props/furniture
assetName = couch

Then we could also check whether all of the paths defined in the rule set exist (but that's relatively easy):

C:/Projects/foo/dev/model/props/furniture/couch/data/obj
C:/Projects/foo/dev/model/props/furniture/couch/data/fbx
C:/Projects/foo/asset/shots/props/furniture/animation/couch/scenes
C:/Projects/foo/asset/shots/props/furniture/rendering/couch/scenes

Here's my current test implementation:

import os
import re

variableRegex = re.compile(":[\w]*:")

def getRules():
    return [":projectRoot:/dev/model/:parentHierarchy:/:assetName:/data/obj",
            ":projectRoot:/dev/model/:parentHierarchy:/:assetName:/data/fbx",
            ":projectRoot:/asset/shots/:parentHierarchy:/animation/:assetName:/scenes",
            ":projectRoot:/dev/model/:parentHierarchy:/:assetName:/data/obj"]

def getVarRules():
    """
        These rules define how many hierarchy depth each variable represents.
        (This is simplified from the actual code I'm working with to ease the example for the question)

        -1 defines that the variable can hold one or more folders (nested folders), thus never zero
        1 defines it will can't have subfolders and will define a single folder
    """
    return {":projectRoot:": -1,
            ":parentHierarchy:": -1,
            ":assetName:": 1}

def reversePath(path, rule):
    """
        Returns the variables within rule by getting them from the path.
        This will only work if the given path is valid for the given rule.

        This is currently a dummy function.
        This is a part where I get stuck. How to slice it up based on the rules?
    """
    varHierarchyDepth = getVarRules()
    return path

def reverseEngineerWorkspaces(path):
    """
        This function should check if the given path is valid for any of the rules.

        Note that static parts (end parts of the rule not defined by a variable) may be omitted from the input path.
        That input path can still be validated (only if the folder exists and contains the required static end as
        subdirectories/files.)
    """
    rules = getRules()
    varHierarchyDepth = getVarRules()

    path = os.path.realpath(path)
    path = path.replace("\\","/")   # force forward slashes so it's similar to our rules definitions.
    path = path.rstrip("/")         # remove any trailing slashes

    for rule in rules:
        # 1.
        # First we check if any of the static parts that are in front of the last variables are present in the path.
        # If not present it certainly isn't the correct path.
        # We skip checking the end static part because we could easily check whether those exist within the current folder
        staticParts = [ part for part in variableRegex.split(rule) if part != "" and part != "/" ]
        if not all([x in path for x in staticParts[:-1]]):
            continue

        if rule.endswith(staticParts[-1]):
            # If this this rule ends with a static part we can use that to check if the given path is fully valid
            # Or if the path concatenated with that static part exists. If so we have a valid path for the rule.
            if path.endswith(staticParts[-1]):
                return reversePath(path, rule)
            else:
                lastPartSubfolders = staticParts[-1].split("/")
                for x in range(len(lastPartSubfolders)):
                    tempPath = os.path.join(path, *lastPartSubfolders[:-x])
                    if os.path.exists(tempPath):
                        return reversePath(tempPath, rule)
        else:
            raise NotImplementedError("There's no implementation for rules without a static end part.")

print reverseEngineerWorkspaces("""C:/Projects/foo/dev/model/props/furniture/couch/data/""")
print reverseEngineerWorkspaces("""C:/Projects/foo/dev/model/props/furniture/couch/data/fbx""")
print reverseEngineerWorkspaces("""C:/Projects/foo/dev/model/props/furniture/couch/data/obj""")
print reverseEngineerWorkspaces("""C:/Projects/foo/asset/shots/props/furniture/animation/couch/scenes""")

Currently it only finds path consisting of the static parts (the variable rules aren't checked, I'm not sure how to add that in here).

And it doesn't parse out the variables from any full path that follows the rule.

1条回答
Explosion°爆炸
2楼-- · 2019-08-28 00:42

I think you can do it all with one regex:

In [24]: re.search(r'(.+)(?:dev/model/|asset/shots/)(.+)/(.+?)(?:/data|/scenes)', path).groups()
Out[24]: ('C:/Projects/foo/', 'props/furniture', 'couch')
查看更多
登录 后发表回答