Select by part of name

Discussion of Photoshop Scripting, Photoshop Actions and Photoshop Automation in General

Moderators: Tom, Kukurykus

Dariusz1989

Select by part of name

Post by Dariusz1989 »

Heya

Pretty silly issue. But it appears to be unbreakable for me :/

I'm trying to select layers by part of name. Well I want to loop thought all of them but I hope that wont be a problem... in any case :


Code: Select allif (newName = layerName.artLayers.getByName("*Rainbow*"));
{
alert(newName)
}



Thanks, bye.

Professional AI Audio Generation within Adobe Premiere Pro - Download Free Plugin here

Mike Hale

Select by part of name

Post by Mike Hale »

As far a I know, getByName doesn't support wildcard chars and only returns exact matches. Even then it only returns the top most layer with that exact name.

I think you will have to loop through all the layers and find the match(s) that way.
Dariusz1989

Select by part of name

Post by Dariusz1989 »

Heya

yea thats what I have atm. But it drops me an error...

Code: Select alldoc = app.activeDocument;

for (var a =0;a<doc.layers.length;a++){
doc.activeLayer = doc.layers[a];
layerName = doc.layers[a].name;

if (newName = layerName.artLayers.getByName("*Rainbow*"));
{
alert(newName)
}
}

I'm getting "undefinied is not an object" umh?
Mike Hale

Select by part of name

Post by Mike Hale »

As I said you can't use getByName to match part of a layer name. Even if you could you wouldn't do it that way. You are assigning the layer name to a variable called 'layerName'. That variable holds a string( the layer's name). It doesn't have an artLayers collection. That is why you are getting the undefined error.

Do something like this
Code: Select alldoc = app.activeDocument;

for (var a =0;a<doc.layers.length;a++){
    var layerName = doc.layers[a].name;
    if (layerName.match(/.*Rainbow.*/)){
        alert(layerName);
    }
}
Dariusz1989

Select by part of name

Post by Dariusz1989 »

Hai !

Right so I hit another wall... and well this is embarasing, I thought I could get it running.

In any case I'm trying now to do the stuff I wanted to do initially.. I sort off got it working one way, but it does not do exactly wahat I wanted. I gues its because the index changes after I run 1st loop and then all goes to hell...

So here is the first line of code:

Code: Select alldoc = app.activeDocument;     
testGRP = doc.layerSets.getByName('Shadows');

for (var a =0;a<doc.layers.length;a++){
    var LN = doc.layers[a].name; 
   
    if (LN.match(/.*IB_Shad*/)){
            var desc = new ActionDescriptor();
        var sourceRef = new ActionReference();
        sourceRef.putName( charIDToTypeID( "Lyr " ), LN );
    desc.putReference( charIDToTypeID( "null" ), sourceRef );
            var indexRef = new ActionReference();
            indexRef.putName( charIDToTypeID("Lyr "), testGRP.name );
            var layerIndex = executeActionGet(indexRef).getInteger(stringIDToTypeID('itemIndex'));
        var destinationRef = new ActionReference();
        destinationRef.putIndex( charIDToTypeID( "Lyr " ), layerIndex-1 );
    desc.putReference( charIDToTypeID( "T   " ), destinationRef );
    desc.putBoolean( charIDToTypeID( "Adjs" ), false );
    desc.putInteger( charIDToTypeID( "Vrsn" ), 5);
    executeAction( charIDToTypeID( "move" ), desc, DialogModes.NO );             
}
   }

it works but it messes up the layers...

The second attempt was this :

Code: Select alldoc = app.activeDocument;     

testGRP = doc.layerSets.getByName('Lights');
for (var a =0;a<doc.layers.length;a++){
    var layerName = doc.layers[a].name;

    if (layerName.match(/.*lit*/)){
    Name = doc.artLayers.getByName(layerName);
    moveIt(doc,Name,testGRP);

    function moveIt(doc, srcLayer, toLayerName) {
        srcLayer.move(toLayerName.ElementPlacement.INSIDE);
}
}
}

And this one give me some error so ehh hilp meee

If I have string and i want to use it with .move I need it to be layer or layerSet as far as I was informed, then how can I convert that string to that thini ? Is this the good approach ? Name = doc.artLayers.getByName(layerName);

Also on a side note regarding searching by name...
How can I search for multiple flags so it only selects the one that it has them all in any order?
.match(/.*lit_*/,/.*specular*/))
.match(/.*lit_*/+/.*specular*/))
.match(/.*lit_*/|/.*specular*/))
.match(/.*lit_,specular*/))
.match(/.*lit_ | specular*/))

I tried these options, none of them work and from internet I read that I might need to use redex so uhhh...

Thanks, bye..
Mike Hale

Select by part of name

Post by Mike Hale »

I'll answer the RegExp part first. There are lots of ways to create a RegExp to match parts of a string. And guessing rarely works so reading about how to use regular expressions would help. But it you just want to match any layer that has 'lit_' or 'specular' any where in the layer name you can do something like this.
Code: Select allif(app.activeDocument.activeLayer.name.match(/lit_|specular/) != null) alert('Match in layer name');
As for the rest, it might be better if you told us what you want to do instead of posting what you have tried and us trying to understand what you want done( and why it's not working ).

But it looks like you are trying to move layers with matching names into a layerSet. I think the best way to do that is with two loops. The first loop searches the layers and stores the matches. Moving, adding, or deleting layers in that loop just causes problems. A second loop of the matching layers is where you move or delete. Something like this.
Code: Select allvar doc = app.activeDocument;     
var testGRP = doc.layerSets.getByName('Lights');// layerSet to move matching layers into
var matchedLayers = [];// array to hold any matching layer objects
// loop to find layers - top level only
for (var a =0;a<doc.layers.length;a++){
        var layerName = doc.layers[a].name;

        if (layerName.match(/lit_|specular/) != null){
            matchedLayers.push(doc.layers[a]);// name matches so store layer object for later
        }
}
// loop any found layers to move
for( var a = 0;a<matchedLayers.length;a++){
            matchedLayers[a].move(testGRP, ElementPlacement.INSIDE);
}
Dariusz1989

Select by part of name

Post by Dariusz1989 »

Heya

Yea I guess that would be a lot simpler if I would just explain up front what I was trying to do... uhh sorry.

On a side note what does this do ? != null ? Atm its finding either lit_ or specular or both. I was wondering if I can tweak it down to lit + specular only rather than them being separated option.

Where would you suggest I could read about searching and string? I think it would be a lot better for me to read doc than my spamming the forum

Thanks, bye.
Mike Hale

Select by part of name

Post by Mike Hale »

As long as your post is about Adobe scripting it's not spam.

Don't be offended but from the code you posted I would suggest you start with reading the scripting guide to understand the Photoshop Object Model. I think that will be more helpful to you than trying to learn Photoshop scripting and RegExp at the same time.

There are tons of books and web sites about RegExp and I don't really have any recommendations. RegExp is all about pattern matching. It should be possible to have an expression that does what you want but before I can suggest something I would need to see some examples of the layer names you want to search/match to see if there is a pattern. For example you want to match both 'lit' and 'specular'. Does 'lit' always come before 'specular'. What about any chars between those two strings. A simple match expression would look something like this

/lit.*specular/

That will match 'lit' followed by 0 or more chars followed by 'specular'. Note case matters. It will not match 'Specular' unless you add the ignore case modifier.

/lit.*specular/i

The != null is a test to see if the match does not equal null. The match() method returns the matching string if there is a match. If there is not a match it returns null. In other words null means not found. Because the matching string depends on the match argument checking that it is not null lets you know there is a match without needing to know the exact matching string.

Similarly if(myString.search(someRE) != -1 ) lets you know there isn't a match when using the search method. If there was a match it returns the starting matching char position. A -1 means not found in this case.

And again, don't worry about posting on topic questions here. This forum exists to help people at all levels of experience.
Dariusz1989

Select by part of name

Post by Dariusz1989 »

Heya

Thanks for help ! Regarding reading the scripting guide. Yes it is on the list. Just with all the stuff that happens around me right now I might just not have as much time as I should give it to...

In any case I went over RegExp and I sort of understand quite a lot more about it now.
I managed to tweak the search parameter so it looks for both of the key worlds and acts only if it find them both....
Is this the correct approach ? it works, but it might be accident

/lit+.*specular./ ?

Also I went over this information + few other regarding regexp but nowhere it says what does this means "/" and "\"... so what does it do ?
http://www.w3schools.com/jsref/jsref_obj_regexp.asp
http://www.w3schools.com/js/js_obj_regexp.asp

Thanks, bye.
Mike Hale

Select by part of name

Post by Mike Hale »

"/" and "\" are just two of the many special chars used in regular expressions. The forward slash is used to start and stop the pattern when creating an implicit RegExp like /lit+.*specular./
That same expression could be created explicitly like this new RegExp(lit+.*specular.). Notice the forward slashes are not used in the last example.

The back slash is used to either give a char a special meaning or take away the special meaning of some chars.

/d/ means match a single 'd' char. /\d/ means match a single digit char( 0-9 )

/./ means match any single char. /\./ means match a single dot char.