Maya/Python: Search and Replace in Python?

what’s the simplest and most straight forward way of replacing a name on objects inside a list?

For a super simple find replace:


import pymel.core as pm
for item in pm.selected():
    item.rename(item.name().replace('find', 'replace'))

[QUOTE=R.White;28430]For a super simple find replace:


import pymel.core as pm
for item in pm.selected():
    item.rename(item.name().replace('find', 'replace'))

[/QUOTE]

So what am I doing wrong here?

import maya.cmds as mc
import pymel.core as pm
#select the chain
selected = mc.ls(sl=True)
#duplicate the original chain
IK_Chain = mc.duplicate()

mc.select(IK_Chain)
for item in pm.selected():
    item.rename(item.name().replace('B_L_', 'IK_B_L_'))

It seems like the root of the problem is the fact that when I duplicate the original joint chain the names stay the same and that pretty much stops me from doing anything.

I basically want to duplicate original chain and add IK_ prefix.

Any ideas?

Figured it out after a very long process of trial and error. Fucking hell

import maya.cmds as mc
#select the chain
selected = mc.ls(sl=True)
#duplicate the original chain
DICK = mc.duplicate(rc=True)
PRICK = mc.select(DICK)
CUNT = mc.ls(sl=True)
for i in CUNT:
    mc.rename(i, 'IK_'+ str(i))

Although this is just for adding prefix. Will probably take me another day to figure out how to replace names…

This is a classic maya annoyance.

You can get around it by using long names and sorting the duplicated objects so that the leaves in the hierarchy come first. Otherwise maya gets very confused about who is who.


dupes = cmds.duplicate()                   #duplicate
dupes = cmds.ls(sl=True, l=True)           # dupes are selected; get their long names
dupes += cmds.listRelatives(dupes, ad=True, f=True) or []  # add any children
dupes = [i for i in reversed(sorted(set(dupes)))]  # sort them in reverse order, leaves first
for d in dupes:
    root,_,  tail =  d.rpartition("|")     # get the shortname from the full name
    newname = tail.replace("L_", "X_")     # do the replacement
    cmds.rename(d, newname)                # rename using the original long name and new short name

1 Like

Thanks for the in-depth explanation.

Being new to Python, there’s nothing worst than seeing all those brackets and parentheses. I will try to make sense of it line by line.

Jesus man, all of this is just one line in Mel :confused: (Which I tried using, but then I couldn’t store mel.eval in a python variable)

It’s not really simpler in Mel - here’s what actually gets called to rename just one node - and there’s a separate function to do them in reverse order!


global proc string addPrefixToName(string $prefix, string $nodeName)
{
	string $result;
	
	if ( "" == $nodeName ) {
		return "";
	}

	int $hasLeadingBar = ("|" == `substring $nodeName 1 1`);
	
	string $path[];
	int $pathLength = `tokenize $nodeName "|" $path`;
	if ( $pathLength > 0 ) {
	
		// Add $prefix to all names in $nodeName.
		//
		int $i = 0;
		for ( $i = 0; $i < $pathLength; $i++ ) {
			$path[$i] = ($prefix + $path[$i]);		
		}
		
		// Build $result from the, now prefixed, elements of $nodeName
		//
		$result = "";
		if ( $hasLeadingBar ) {
			$result = "|";
		}
		$result += $path[0];
		for ( $i = 1; $i < $pathLength; $i++ ) {
			$result += "|" + $path[$i];	
		}
	}
	
	return $result;
}

I realized though you can make it much simpler:


long_and_short = zip(cmds.ls(sl=True, l=True), cmds.ls(sl=True))
long_and_short.sort()
long_and_short.reverse()
renamed =[cmds.rename(long, "PREFIX_" + short) for long, short in long_and_short]


You can actually avoid the reverse() method, as sort has an optional reverse keyword argument.


long_and_short = zip(cmds.ls(sl=True, l=True), cmds.ls(sl=True))
long_and_short.sort(reverse=True)
renamed =[cmds.rename(long, "PREFIX_" + short) for long, short in long_and_short]

I meant that I could just do this in mel to achieve the same result:

mm.eval('searchReplaceNames _L_ _R_ hierarchy')

Hey badcat,

This may or may not be of use to you but you could always try using something like ‘cometRename’ in order to deal with renaming objects. Trust me, this tool will pretty much solve 99% of your problems, at least when it comes to finding an alternative for Maya’s Search and Replace tool.

It’s been a while since I’ve needed to download these tools so hopefully the link below works:
http://www.comet-cartoons.com/melscript.php


Do you solve the rename thing?

my search and rename just get a iterate name of hierarchy, like the parent name l_armIkRoot_jnt, the children name will be the parent name + children’s name: l_armIkRoot_jnt_l_armIkMid_jnt. How can I get rid of the parent name from the children’s name?

cmds.duplicate(un=True)
selected = cmds.ls(sl=True, sn=True)

for i in selected:
    name = i.replace("arm", "armIk").replace("wrist", "wristIk").replace("jnt1", "jnt")
    cmds.rename(name)

When you get a name, if you use the -long flag in ls you will get the entire hierarchy:

 ls('head', long=True)
#   |root|spine_01|spine_02|spine_03|neck_01|neck_02|head

If you’re getting unwanted tokens in your name, you can use this to find out what the parent was while assigning a new name:

 def  name_without_parent(node):
       parents = cmds.ls(node, long=True).split("|") 
       if len(parents) == 1:
          return node  #no parent, do nothing

      node_name = parents[-1]
      parent_name = parents[-2]
       
       try:
            parent_index = node_name.index(parent_name)
            return node_name[parent_index:]
       except:
            return node # parent name does not appear in name, do nothing

Thank your answers! I didn’t use your way but it’s nice to know the methods.
I solved the problems by use:
indexList = cmds.ls(sl=True, tr=True, s=False)