具有区分大小写的Python字符串模板化(Python String Templating with Case Sensitivity)

编程入门 行业动态 更新时间:2024-10-28 16:22:18
具有区分大小写的Python字符串模板化(Python String Templating with Case Sensitivity)

这是一个命名脚本,用于命名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_joint

And 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_joint

Edit: 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_joint

not

>> bind___thigh__left____joint

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?

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 collections

We 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 mapping

We 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_name

And 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_JOINT

Update #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}01

We used the power of backreferences here i.e. with \g<group_number>. Check the docs here for more information on backreferences in regular expressions.

更多推荐

本文发布于:2023-08-05 20:19:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1439037.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:大小写   字符串   模板   Python   Sensitivity

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!