这是一个命名脚本,用于命名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'This is a naming script that i use to name nodes in Autodesk Maya. This particular script however doesnt use anything maya specific.
I had asked a while ago how I would go about doing something like this, where a variable convention could be used, and templating came up.
So if i had a convention like this:
'${prefix}_${name}_${side}_${type}'I could pass these arguments:
bind_thigh_left_jointAnd then run them through an abbreviation dictionary (as well as a user abbreviation dictionary), check it with relevant nodes in scene file to make sure there are no duplicates, and end up with this: bn_thigh_L_jnt
However I wanted it so that if one of the keys has a first uppercase letter, it would make the substitute uppercase.
For example if {$prefix} was instead {$Prefix} thigh would become Thigh, or if {$prefix} was {$PREFIX} thigh would become THIGH. However if it was {$PREfix} thigh would still only be Thigh.
I can do this easily enough except that I have no way to detect the individual cases of the keys. For example, if the string is '${Prefix}_${name}_${SIDE}_${type}' How would I find what case prefix is, and if i knew that, how would i use that with this template?
Note this code isnt the exact code i have, I have ommitted a lot of other stuff that was more maya specific, this just deals with the substituting itself.
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_jointEdit: Also would like to strip multiple underscores
So if I had something like:
'${prefix}___${name}__${side}_____${type}'I would want it to come out
>> bind_thigh_left_jointnot
>> bind___thigh__left____jointAlso the last thing, I figured since a user would be inputting this, it would be more convenient not to be adding brackets and dollar signs. Would it be possible to do something like this?
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'最满意答案
在这里,我们可以使用OOP的强大功能使模板做到我们想要的。 我们可以继续扩展string.Template类(如文档中所示 )。
我们先导入一些相关的方法/类:
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:
如果要处理用户约定中多次出现的下划线_和可能的特殊字符,只需在convert()方法的return语句之前添加以下行:
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命令都有标志来控制返回名称的详细程度(即egs。WITH namespace,完整DAG路径,或者这些都没有)。
更新#2:
对于问题的扩展部分,您曾询问过:
最后一件事,我想,因为用户会输入这个,所以更方便的是不添加括号和美元符号。 可以这样做吗?
是。 事实上,为了进一步概括,如果你假设模板字符串只有alpha而不是字母数字,你可以再次使用re从user_conv取出它们并将它们user_conv ${}里面,如下所示:
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> 。 有关正则表达式中反向引用的更多信息,请查看此处的文档 。
Here, we can use the power of OOP to make the template do what we want to. We can go ahead and extend the string.Template class (as suggested in the docs).
Let us first import some relevant methods/classes:
from string import Template, uppercase, _multimap import collectionsWe then define a helper method for dealing with arguments passed to the safe_substitute() or substitute() method. (The meat for this method was taken from Python's string module source):
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 mappingWe then go ahead and define our extended Template class. Let us call this class CustomRenameTemplate. We write a helper method called do_template_based_capitalization(), that basically does the capitalization based on the template pattern you have provided. We make sure we override the substitute() and safe_substitute() methods to use this.
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)We are ready to use this class now. We go ahead and do some slight modifications to your convert() method to put this new class into action:
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_nameAnd here's it in action:
>>>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_JOINTUpdate #1:
If you want to deal with multiple occurrences of the underscore _ and possible special characters in the user convention, just add the following lines before the return statement of the convert() method:
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 _Note: An important thing to consider when stripping away special characters is the special characters used by Maya egs. for namespace representation : and for hierarchy representation |. I will leave it up to you to either choose to strip these away, or replace them with another character, or to not receive them in the first place. Most Maya commands that return an object name(s) have flags to control the verbosity of the name returned (i.e. egs. WITH namespace, full DAG path, or none of these).
Update #2:
For the extended portion of your question, where you had asked:
Also the last thing, I figured since a user would be inputting this, it would be more convenient not to be adding brackets and dollar signs. Would it be possible to do something like this?
Yes. In fact, to generalize that further, if you assume that the template strings will only by alpha and not alpha-numeric, you can again use re to pick them up from the user_conv and stuff them inside ${} like so:
user_conv = 'PREFIX_name_Side_TYPE01' user_conv = re.sub('[A-Za-z]+', '${\g<0>}', user_conv) >>> print user_conv >>> ${PREFIX}_${name}_${Side}_${TYPE}01We used the power of backreferences here i.e. with \g<group_number>. Check the docs here for more information on backreferences in regular expressions.
更多推荐
发布评论