具有区分大小写的Python字符串模板

时间:2015-03-04 09:40:41

标签: python python-2.7 maya

这是一个命名脚本,用于命名Autodesk Maya中的节点。然而,这个特殊的脚本并没有使用特定的任何东西。

我刚才问过我会怎么做这样的事情,可以使用变量约定,然后出现模板。

所以如果我有这样的约定:

'${prefix}_${name}_${side}_${type}'

我可以传递这些论点:

bind_thigh_left_joint

然后通过缩写词典(以及用户缩写词典)运行它们,使用场景文件中的相关节点进行检查以确保没有重复项,最后得到:bn_thigh_L_jnt

但是我想要它,以便如果其中一个键具有第一个大写字母,它将使替换大写。

例如,如果{$prefix}代替{$Prefix}大腿会变成大腿,或者{$prefix}{$PREFIX}大腿会变成大腿。但是,如果{$PREfix}大腿仍然只是大腿。

我可以很容易地做到这一点,除了我无法检测钥匙的个别情况。例如,如果字符串是'${Prefix}_${name}_${SIDE}_${type}'我怎样才能找到什么案例前缀,如果我知道,我将如何使用此模板?

请注意,这段代码不是我所拥有的确切代码,我已经省略了许多其他更具特色的东西,这只是处理替换本身。

from string import Template
import collections

def convert(prefix, name, side, obj_type):
    user_conv = '${Prefix}_${name}_${SIDE}_${type}'
    # Assigns keys to strings to be used by the user dictionary.
    subs = {'prefix': prefix, 'name': name, 'side': side, 'type': obj_type}

    # Converts all of user convention to lowercase, and substitutes the names from subs.
    new_name = Template(user_conv.lower())
    new_name = new_name.safe_substitute(**subs)
    # Strips leading and trailing underscores, and replaces double underscores with a single
    new_name = new_name.strip('_')
    new_name = new_name.replace('__', '_')

    return new_name

print convert('bind', 'thigh', 'left', 'joint')
>> bind_thigh_left_joint

编辑: 还想剥去多个下划线

所以,如果我有类似的东西:

'${prefix}___${name}__${side}_____${type}'

我希望它出来

>> bind_thigh_left_joint

>> bind___thigh__left____joint

也是最后一件事,我想,因为用户会输入这个,所以不添加括号和美元符号会更方便。是否可以做这样的事情?

import re
user_conv = 'PREFIX_name_Side_TYPE01'
# do all filtering, removing of underscores and special characters
templates = ['prefix', 'name', 'side', 'type']
for template in templates:
    if template in user_conv.lower():
        # add bracket and dollar sign around match

>> '${PREFIX}_{name}_{Side}_${TYPE}01'

2 个答案:

答案 0 :(得分:7)

在这里,我们可以使用OOP的强大功能使模板做我们想做的事情。我们可以继续扩展string.Template类(如docs中所述)。

让我们先导入一些相关的方法/类:

from string import Template, uppercase, _multimap
import collections

然后我们定义一个帮助方法来处理传递给safe_substitute()substitute()方法的参数。 (此方法的内容来自Python的string模块源代码):

def get_mapping_from_args(*args, **kws):
    if len(args) > 1:
        raise TypeError('Too many positional arguments')
    if not args:
        mapping = kws
    elif kws:
        mapping = _multimap(kws, args[0])
    else:
        mapping = args[0]             
    return mapping

然后我们继续定义扩展的Template类。我们称这个班为CustomRenameTemplate。我们编写了一个名为do_template_based_capitalization()的辅助方法,它基本上根据您提供的模板模式进行大写。我们确保覆盖substitute()safe_substitute()方法以使用此功能。

class CustomRenameTemplate(Template):    
    def __init__(self, *args, **kws):        
        super(CustomRenameTemplate, self).__init__(*args, **kws)
        self.orig_template = self.template
        self.template = self.template.lower()    

    def do_template_based_capitalization(self, mapping):
        matches = self.pattern.findall(self.orig_template)
        for match in matches:
            keyword = match[self.pattern.groupindex['braced']-1]
            if keyword[0] in uppercase:  # First letter is CAPITALIZED
                if keyword == keyword.upper():  # Condition for full capitalization
                    mapping[keyword.lower()] = mapping[keyword.lower()].upper()
                else:  # Condition for only first letter capitalization
                    mapping[keyword.lower()] = mapping[keyword.lower()].capitalize()   

    def safe_substitute(self, *args, **kws):
        mapping = get_mapping_from_args(*args, **kws)
        self.do_template_based_capitalization(mapping)
        return super(CustomRenameTemplate, self).safe_substitute(mapping)

    def substitute(self, *args, **kws):
        mapping = get_mapping_from_args(*args, **kws)
        self.do_template_based_capitalization(mapping)
        return super(CustomRenameTemplate, self).substitute(mapping)

我们现在准备好使用这个课程。我们继续对您的convert()方法进行一些细微的修改,以便将这个新类付诸行动:

def convert(prefix, name, side, obj_type, user_conv='${Prefix}_${name}_${SIDE}_${type}'):
    # Let us parameterize user_conv instead of hardcoding it.
    # That makes for better testing, modularity and all that good stuff.
    # user_conv = '${Prefix}_${name}_${SIDE}_${type}'
    # Assigns keys to strings to be used by the user dictionary.
    subs = {'prefix': prefix, 'name': name, 'side': side, 'type': obj_type}

    # Converts all of user convention to lowercase, and substitutes the names from subs.
    new_name = CustomRenameTemplate(user_conv)  # Send the actual template, instead of it's lower()
    new_name = new_name.substitute(**subs)

    # Strips leading and trailing underscores, and replaces double underscores with a single
    new_name = new_name.strip('_')
    new_name = new_name.replace('__', '_')

    return new_name

这就是它的实际效果:

>>>print convert('bind', 'thigh', 'left', 'joint')
Bind_thigh_LEFT_joint

>>>print convert('bind', 'thigh', 'left', 'joint', user_conv='${prefix}_${name}_${side}_${type}')
bind_thigh_left_joint

>>>print convert('bind', 'thigh', 'left', 'joint', user_conv='${prefix}_${NAme}_${side}_${TYPE}')
bind_Thigh_left_JOINT

更新#1:

如果要在用户约定中处理多次出现的下划线_和可能的特殊字符,只需在return方法的convert()语句之前添加以下行:

new_name = re.sub('[^A-Za-z0-9_]+', '', new_name)  # This will strip every character NOT ( NOT is denoted by the leading ^) enclosed in the []
new_name = re.sub('_+', '_', new_name)  # This will replace one or more occurrences of _ with a single _

注意:的 剥离特殊字符时要考虑的一个重要事项是Maya egs使用的特殊字符。用于名称空间表示:和层次结构表示|。我将把它留给你去选择剥离它们,或者用另一个角色替换它们,或者首先不接收它们。返回对象名称的大多数Maya命令都有标志来控制返回的名称的详细程度(例如,例如.WES名称空间,完整的DAG路径,或者没有这些)。

更新#2:

对于问题的扩展部分,您曾问过:

  

也是最后一件事,我想,因为用户会输入这个,   不添加括号和美元会更方便   迹象。是否可以做这样的事情?

是。事实上,为了进一步概括,如果你假设模板字符串只有alpha而不是字母数字,你可以再次使用reuser_conv中取出它们并将它们填入${} {1}}喜欢这样:

user_conv = 'PREFIX_name_Side_TYPE01'
user_conv = re.sub('[A-Za-z]+', '${\g<0>}', user_conv)

>>> print user_conv
>>> ${PREFIX}_${name}_${Side}_${TYPE}01

我们在这里使用反向引用的强大功能,即使用\g<group_number>。有关正则表达式中反向引用的更多信息,请查看docs here

答案 1 :(得分:1)

为您要支持的每个大小写创建重复替换。使用subsdict.items()循环原始dict.iteritems()字典中的键/值对。使用'KEY': 'VALUE''Key': 'Value'可以轻松创建.upper().title()对。

如果支持'KEy': 'Value'对您来说非常重要,可以通过循环键的索引,拆分,上限第一部分和重新组合来完成。例如,如果key'Hello'

key[:2].upper() + key[2:]

将是'HEllo'

然后,正常使用safe_substitute