• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Create an array of arrays from a .txt file!

LEGEND ,
Nov 03, 2016 Nov 03, 2016

Copy link to clipboard

Copied

Hi all scripters,

The beginning is a .txt file containing data as:

text_1;text_12

text_2;text_23

text_3;text_39

I'm able to get an array as:

[text_1;text_12, text_2;text_23, text_3;text_39, …]

But I need that:

[ ["text_1","text_12"], ["text_2","text_23"], ["text_3","text_39"], …]

I've absolutely no idea about the way to get this array of arrays!!

Thanks for your ideas!

(^/)

TOPICS
Scripting

Views

3.4K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Uwe and Swo,

I agree with both of you! 

Uwe is totally right!  "With Great Power Comes Great Responsibility!"

My Master Yoda would have said:

"Powerful the Force is! Powerful Javascript and Grep are also!

Easy is to go to the dark side and errors make!

The errors we must tame!"

(^/) 

I think the user has to first control his list quality! [as Uwe enumerated greatly!]

An alert [Ok to continue, Cancel to abort] could tell him: "Your list must be as …!"

Imho, the real problem the script could encounter is when a layer name already exists, as:

Capture d’écran 2016-11-06 à 21.13.59.png

The concordances list is:

Layer_1;Layer_8

Layer_2;Layer_9

As you can see, there's a problem with Layer_8!

So, as Uwe did, I've taken his code and inserted a double if:

myList = ["Layer_1;Layer_8","Layer_2;Layer_9"]; 

myLayers = app.activeDocument.layers; 

for ( L = 0; L < myList.length; L++ ) {

    var error = false; 

    parts = myList.split (';');

    if ( myLayers.everyItem().name.join(";").match(parts[1]) ){ error = true }; 

        if( error ){

            alert ( "This layer name '" + parts[1] + "' already exist! \rThe script is going to abort! Correct it!\r(^/)  ;-)" );

            exit();

        }

    myLayers.item(parts[0]).name = parts[1];

}

Thanks for your comments! [I go on to study!]

(/^)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Uwe,

I need to study more what you wrote in post#19!

My way above is not really cool! 

(^/)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

That seems to be an interesting, surely bad written, approach:

app.doScript(main, ScriptLanguage.JAVASCRIPT, [], UndoModes.ENTIRE_SCRIPT, "Rename Layers By List! …");

function main ()     

{

    var myLayers = app.activeDocument.layers,

    P = myLayers.length,

    myList = ["Layer_3;Layer_2","Layer_2;Layer_8","Layer_8;Layer_1","Layer_1;Layer_4","Layer_4;Layer_7","Layer_7;Layer_5","Layer_6;Layer_6","Layer_5;Layer_3"],

    N = myList.length;

        while ( N-- ) myList = myList  + " ";

        for ( N = 0; N < myList.length; N++ ) {

        parts = myList.split (';');

        myLayers.item(parts[0]).name = parts[1];

        }

        while ( P-- && myLayers

.name.slice(-1) == "x" ) myLayers

.name = myLayers

.name.slice(0,-1);

}

Before/After:

Capture d’écran 2016-11-06 à 22.38.31.png   Capture d’écran 2016-11-06 à 22.38.46.png

Of course, if bad list! … So, I suppose by default the list is correct! 

Thanks for your comments!

(^/)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Hu...

Are you adding spaces to new names ?

while ( N-- ) myList = myList  + " "

If thoses layers are renamed and you add invisible spaces in those new names, and those new layers names are part of a more complexe script used later, it will fail.

Swo

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Yes! but I remove them at the end [code line 15]! [new script version, previous is wrong!]

app.doScript(main, ScriptLanguage.JAVASCRIPT, [], UndoModes.ENTIRE_SCRIPT, "Rename Layers By List! …");

function main ()     

{

    var myLayers = app.activeDocument.layers,

    P = myLayers.length,

    myList = ["Layer_3;Layer_2","Layer_2;Layer_8","Layer_8;Layer_1","Layer_1;Layer_4","Layer_4;Layer_7","Layer_7;Layer_5","Layer_6;Layer_6","Layer_5;Layer_3"],

    N = myList.length;

        while ( N-- ) myList = myList  + " ";

        for ( N = 0; N < myList.length; N++ ) {

        parts = myList.split (';');

        myLayers.item(parts[0]).name = parts[1];

        }

        while ( P-- ) if ( myLayers

.name.slice(-1) == " " )  myLayers

.name = myLayers

.name.slice(0,-1);

}

I've added 2 new layers (9 & 10) not included in the list.

Capture d’écran 2016-11-06 à 23.29.25.png   Capture d’écran 2016-11-06 à 23.29.35.png

(^/)  Thanks for your script last version [post#33]! 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

while-loops are used when you don't know how many items you're processing. If you do know the number of items (e.g. in an array), then use a for-loop because for-loops execute quicker than while-loops. What you're up to with those two while loops is beyond me, but never mind.

What you do in that last while-loop (which should really be a for-loop), this:

if ( myLayers

.name.slice(-1) == " " )  myLayers

.name = myLayers

.name.slice(0,-1);

can be done as follows, which is probably quicker:

myLayers

.name = myLayers

.name.replace(/ $/,'');

Peter

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Thanks Peter!

// ID is close for me at the moment! I can't test!

If I want to add a space at the end of the layers name, can I use this:

myLayers

.name = myLayers

.name.replace(/$/,' ');

(^/)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Yes, you can. If only InDesign's grep could do things like that.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Aha! So not this! …

(^/)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Ok, sorry, I didn't saw the line.

Won't you get an error if there's another layer with the same name ?

Didn't you forget the space before $ ?

myLayers

.name = myLayers

.name.replace(/ $/,'');

Swo

(hightlight syntax is messy with this line)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Swo,

As I said, I suppose that the Concordances list is correct!

So, no layer with the same name!

About the syntax Peter show at post#35, I totally like it because it treats Layer_1 to 8 (contained in the list), not Layers_9 and 10.

That means this code includes in itself the "if". It's really cool!

About my last question, It's about this line:

myList = myList  + " "

… when I add a space at the end of each item of the "Concordances list" array!

Could we write this differently with a similar grep syntax as Peter's one? Good question! 

(^/)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

You could use e grep to add a space at the end:

myList = myList.replace(/$/,' ');

but that would be pretty inefficient. The quickest (both to type and to execute) I'm sure is this:

myList += ' ';

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

myList += ' ';

Yes, of course!

Thanks a lot Peter!

(^/)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

> Won't you get an error if there's another layer with the same name ?

Absolutely.

> Didn't you forget the space before $ ?

With JavaScript's GREP you can insert characters at an insertion point, so to speak, which isn't possible in InDesign's GREP. So for example you can do this in JavaScript:

'abc123'.replace(/(?=\d+)/,'#');

to add a # before a number. And you can do this:

'abc123'.replace(/^/,'@');

to add a # at the beginning of a string.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

That's really cool! 

… So, if I want to add a # at the end:

'abc123'.replace(/$/,'#')

Correct?

(^/)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Just try it, mon brave -- be brave!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Hello,

That's really interesting Peter, I can't remember reading about this.

Now I've got a new exercice: reveiwing my scripts and searching to modify accordingly if needed 

Swo

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Obi-wan,

I really like :

"Powerful the Force is! Powerful Javascript and Grep are also!

Easy is to go to the dark side and errors make!

The errors we must tame!"

And I would add :

"And great scripts must have!"

An alert ([Ok to continue, Cancel to abort] could tell him: "Your list must be as …!") would teach us users to be carefull with the text file content.

Too many can be anoying too...

Perhaps you can play with a "while" (be carefull, those are tricky), to rename the layer adding a +" 2", +" 3" or +" copy 1", +" copy 2"... in the name.

if (myLayers.name == oNames && !app.activeDocument.layers.itemByName(nNames).isValid) {

    // renaming, etc.

    ...

}

This part would change for:

if (myLayers.name == oNames) {

    // "a" will increase until there's no more layer with the same name

    var a = "2";

    // testName will change value until it's an unique layer name

    var testName = nNames;

    while (app.activeDocument.layers.itemByName(testName).isValid) {

        testName = nNames + " " + a;

        a++;

    }

    myLayers.name = testName;

    // list renamed layers

    rNames.push(oNames + " => " + testName);

    // ensure old name doesn't conflict with same new name :

    oNames = "";

    testN = true;

    c++;

}

This feels more like a puzzle now

Have fun,

Swo

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Swo,

Right!  A puzzle now! 

Could you post your last version! Thanks!

(^/)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Here it is:

//DESCRIPTION:Rename layers from text file

/*

Text file should contains 2 columns (old name;new name), line by line

separator is ";", can be changed at line 27

If script is unable to find layer_names.txt, it asks for a file.

No check for forbidden characters in names:

you need to check the text file before running the script.

*/

(function () {

    if (app.locale.toString() == "FRENCH_LOCALE") {

        var infos = {

            findFile:"Choisir le fichier contenant la liste de noms :",

            msg:" calque(s) renommé(s) :"

        };

    } else {

        var infos = {

            findFile:"Select the text file for layer names:",

            msg:" layer(s) renamed:"

        };

    }

    // Modify text file's name and separator (sepa) if needed

    var txtList = "layer_names.txt",

        sepa= ";";

   

    var oNames = [], nNames = [], rNames = [];

    var myListFile = File(myFindFile(txtList));

    // datas

    var testNames = listNames();

    if (testNames && oNames.length == nNames.length) {

        var myLayers = app.activeDocument.layers, c = 0;

       

        for (var L = 0; L < myLayers.length; L++) {

            var testN = false;

            for (var n = 0; n < oNames.length && !testN; n++) {

                if (myLayers.name == oNames) {

                    // "a" will increase until there's no more layer with the same name

                    var a = "2";

                    // testName will change value until it's an unique layer name

                    var testName = nNames;

                    while (app.activeDocument.layers.itemByName(testName).isValid) {

                        testName = nNames + " copy " + a;

                        a++;

                    }

                    myLayers.name = testName;

                    // list renamed layers

                    rNames.push(oNames + " => " + testName);

                    // ensure old name doesn't conflict with same new name :

                    oNames = "";

                    testN = true;

                    c++;

                }

            } // for n

        } // for L

        alert(c + infos.msg + "\n" + rNames.join("\n"));

    }

    function listNames() {

        // Open the file for reading

        myListFile.open("r");

        var text = myListFile.read();

        var lines = text.split("\n");

        if (lines.length > 0) {

            for (var y =0; y < lines.length; y++) {

                var l = lines;

                if (l.length != 0) {

                    if (l[0] !== "") {

                        var names = l.split(sepa);

                        if (names.length == 2) {

                            oNames.push(names[0]);

                            nNames.push(names[1]);

                        }

                    }

                } // l.length

            } // for

            return true;

        } // lines.length

        return false;

    }

    //////// FUNCTIONS ////////////

    function myFindFile(myFilePath) {

        var myScriptFile = myGetScriptPath();

        var myScriptFile = File(myScriptFile);

        var myScriptFolder = myScriptFile.path;

        myFilePath = myScriptFolder + "/" + myFilePath;

        if(File(myFilePath).exists == false) {

            //Display a dialog.

            myFilePath = File.openDialog(infos.findFile);

        }

        // else alert("ok");

        return myFilePath;

    }

    function myGetScriptPath() {

        try {

            myFile = app.activeScript;

        }

        catch(myError){

            myFile = myError.fileName;

        }

        return myFile;

    }

}());

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 07, 2016 Nov 07, 2016

Copy link to clipboard

Copied

Hi Obi-wan,

in answer # 19 I showed a use case.

1-BeforeRenaming.png

Here the script that did the renaming:

/**

* @@@BUILDINFO@@@ RenamingLayers-Using-LIST-OldName-NewName.jsx !Version! Sun Nov 06 2016 13:45:33 GMT+0100

*/

// Uwe Laubender

// Make sure, that the separator character below is not used in a regular layer name.

// "oldName;newName" would perhaps not work, because ; could be part of oldName ( or newName ).

// I've seen a lot when it comes to naming layers with customer documents.

// There might be better separator characters than this one:

var notUsedCharacterInNames = ";";

// Scheme: oldName+notUsedCharacterInNames+newName

var listArray =

    [

        "Layer_1"+notUsedCharacterInNames+"Layer_5",

        "Layer_2"+notUsedCharacterInNames+"Layer_4",

        "Layer_4"+notUsedCharacterInNames+"Layer_2",

        "Layer_5"+notUsedCharacterInNames+"Layer_1"

    ];

var myDoc = app.documents[0];

var allLayersOfDoc = myDoc.layers.everyItem().getElements();

// Explained later:

var associativeArray = [];

var notRenamedLayersIDs = [];

var regExp = new RegExp("^\\d+"+notUsedCharacterInNames);

// IMPORTANT:

// Be aware to preprocess the list entries.

// There is no trailing white space allowed in layer names with the UI.

// Also no one can copy/paste trailing white space to layer names!

// And using an empty string "" as name is only possible by scripting.

// AND A LIST CAN PROVIDE YOU WITH ALL SORT OF CHARACTERS OR AN EMPTY STRING.

// WARNING! This script does no preprocessing of the provided list!

// 1. Feed the associativeArray with a key/value pair by looping the listArray:

for(var n=0;n<listArray.length;n++)

{

    var oldName = listArray.split(notUsedCharacterInNames)[0];

    var newName = listArray.split(notUsedCharacterInNames)[1];

  

    associativeArray[oldName] = newName;

};

// 2. Rename existing layers.

// Naming scheme: n+_oldName

for(var n=0;n<allLayersOfDoc.length;n++)

{

    allLayersOfDoc.name =

    n+notUsedCharacterInNames+allLayersOfDoc.name;

};

// 2. Loop the layers of the document

// 2.1 Check, if the old name is in the associative array

// 2.2 If not, store its ID number in the notRenamedLayersIDs array.

// And loop on with continue.

// 2.3. If it can be found in the associative array,

// rename it with the new name stored in the associative array.

for(var n=0;n<allLayersOfDoc.length;n++)

{

    var nameToTest = allLayersOfDoc.name.replace(regExp,"");

    // Is that name NOT in the associative array?

    if(associativeArray[nameToTest] == undefined)

    {

        // Then do not rename that layer, but remember it:

        notRenamedLayersIDs[notRenamedLayersIDs.length++] = allLayersOfDoc.id;

        // Loop on:

        continue

    };

    // Alright, the name was found as key,

    // let's rename the layer to the key's value:

    allLayersOfDoc.name =

    associativeArray[nameToTest];

};

// What's left to do?

// Setting back the name of the layers that need no new names according to the provided list:

for(var n=0;n<notRenamedLayersIDs.length;n++)

{

    myDoc.layers.itemByID(notRenamedLayersIDs).name =

    myDoc.layers.itemByID(notRenamedLayersIDs).name.replace(regExp,"");

};

Result:

2-AfterRenaming.png

Regards,
Uwe

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 07, 2016 Nov 07, 2016

Copy link to clipboard

Copied

LATEST

Hello,

And nice script...

If I had to use this script, I would need more :

  1. A "pre-script" giving a "layers_names_list.txt", (usable in a spreadsheet)
  2. A final repport for checking for renamed / not renamed layers...

Too bad I don't need such a script

Swo

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 05, 2016 Nov 05, 2016

Copy link to clipboard

Copied

I made a typo :

please correct line 11 :

nodoc:"Select the text file for layer names." 

should be :

findFile:"Select the text file for layer names." 

and line 28 would be better checking for existing layer:

if (myLayers.name == oNames && !app.activeDocument.layers.itemByName(nNames).isValid) {

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 06, 2016 Nov 06, 2016

Copy link to clipboard

Copied

Hi,

Here my “obscure” version with error-handling and a final pop-up listing which layer was renamed.

I hope I'll be able to write as fine scripts as you do Peter,

Swo

//DESCRIPTION:Rename layers from text file

/*

Text file should contains 2 columns (old name;new name), line by line

separator is ";", can be changed at line 27

If script is unable to find layer_names.txt, it asks for a file.

No check for forbidden characters in names:

you need to check the text file before running the script.

*/

(function () {

    if (app.locale.toString() == "FRENCH_LOCALE") {

        var infos = {

            findFile:"Choisir le fichier contenant la liste de noms :",

            msg:" calque(s) renommé(s) :"

        };

    } else {

        var infos = {

            findFile:"Select the text file for layer names:",

            msg:" layer(s) renamed:"

        };

    }

    // Modify text file's name and separator (sepa) if needed

    var txtList = "layer_names.txt",

        sepa= ";";

  

    var oNames = [], nNames = [], rNames = [];

    var myListFile = File(myFindFile(txtList));

    // datas

    var testNames = listNames();

    if (testNames && oNames.length == nNames.length) {

        var myLayers = app.activeDocument.layers, c = 0;

      

        for (var L = 0; L < myLayers.length; L++) {

            var testN = false;

            for (var n = 0; n < oNames.length && !testN; n++) {

                if (myLayers.name == oNames && !app.activeDocument.layers.itemByName(nNames).isValid) {

                    myLayers.name = nNames;

                    // list renamed layers

                    rNames.push(oNames + " => " + nNames);

                    // ensure old name doesn't conflict with same new name :

                    oNames = "";

                    testN = true;

                    c++;

                }

            } // for n

        } // for L

        alert(c + infos.msg + "\n" + rNames.join("\n"));

    }

    function listNames() {

        // Open the file for reading

        myListFile.open("r");

        var text = myListFile.read();

        var lines = text.split("\n");

        if (lines.length > 0) {

            for (var y =0; y < lines.length; y++) {

                var l = lines;

                if (l.length != 0) {

                    if (l[0] !== "") {

                        var names = l.split(sepa);

                        if (names.length == 2) {

                            oNames.push(names[0]);

                            nNames.push(names[1]);

                        }

                    }

                } // l.length

            } // for

            return true;

        } // lines.length

        return false;

    }

    //////// FUNCTIONS ////////////

    function myFindFile(myFilePath) {

        var myScriptFile = myGetScriptPath();

        var myScriptFile = File(myScriptFile);

        var myScriptFolder = myScriptFile.path;

        myFilePath = myScriptFolder + "/" + myFilePath;

        if(File(myFilePath).exists == false) {

            //Display a dialog.

            myFilePath = File.openDialog(infos.findFile);

        }

        // else alert("ok");

        return myFilePath;

    }

    function myGetScriptPath() {

        try {

            myFile = app.activeScript;

        }

        catch(myError){

            myFile = myError.fileName;

        }

        return myFile;

    }

}());

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines