Layers Rename From CSV

Script for Adobe InDesign or Adobe Illustrator

The script reads a spreadsheet of layer names to find, and changes each layer name found to a new layer name.

  • Change the name of any number of layers
  • Layers not in CSV are untouched
  • Save current layer names as CSV to prepare
Download
Layers Rename From CSV

FREE to download
Please make a contribution

Many scripts are free to download thanks to the support of users. Help me keep developing new scripts by supporting my work. Click the button to make a contribution of any amount. Thank you.

How-to Video

Before using the script

The script requires a spreadsheet of find/change pairs, saved as Comma Separated Values (CSV format). The spreadsheet must have at least two columns, one for the layer name to find, and another for its new layer name.

Layers Rename From CSV data example

The first row is the header, which identifies the contents of each column. In this example, the column headers are Find and Change. Using this data file, the script looks for a layer named “708LTRK_DISCM_P8_22C”, and if found, renames the layer to “720ATL_DISCM_P9_22T”, and so on.

These columns could just as well be labeled “match” and “replace,” or any other desired labels. The precise column labels, or their order, are not important, and there is no harm in extra columns. Which column is the layer to find, and which is the new name, are selected in the script interface.

How to use the script

The interface is divided into two sections: Data file, and Export current layer names.

Data File (CSV)

Delimiter — the character that separates columns of the data file. The default is comma, normal in the United States. Some European countries use semicolon rather than comma. Select the delimiter used in your region of the world.

File — select the CSV data file, then the column drop-down lists (next) are loaded with the columns discovered in the data.

Column find — select the column of layer names to find.

Column change — select the column of new layer names.

Export current layer names

This option is to help users prepare the CSV file the script requires. Click the button File then choose a location and name for the file to export. This produces a CSV file with the first column loaded with the current layer names. The “change” column is empty, ready for new names. Copy the current layer names to other text editing tools to search and replace or use regular expressions to alter the current layer names, then paste the new names into the “change” column. Now the CSV file is ready for the script to run and rename the layers.

Source code

(download button below)

/*

Layers Rename From CSV
Copyright 2022 William Campbell
All Rights Reserved
https://www.marspremedia.com/contact

Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

*/

(function () {

    var title = "Layers Rename From CSV";

    if (!/illustrator|indesign/i.test(app.name)) {
        alert("Script for Illustrator or InDesign", title, false);
        return;
    }

    // Script variables.
    var changes;
    var columnIndex;
    var dataArray;
    var defaultSettings;
    var doc;
    var doneMessage;
    var error;
    var finds;
    var working;

    // Reusable UI variables.
    var g; // group
    var gc1; // group (column)
    var gc2; // group (column)
    var p; // panel
    var w; // window

    // Permanent UI variables.
    var btnCancel;
    var btnFileData;
    var btnFileExport;
    var btnOk;
    var listColumnNames;
    var rbComma;
    var rbSemicolon;
    var txtFileData;

    // SETUP

    // Define script variables.
    changes = [];
    columnIndex = [
        // 0 find
        // 1 change
    ];
    dataArray = [];
    finds = [];
    // Define UI variables.
    listColumnNames = [
        // 0 find
        // 1 change
    ];

    // Script requires open document.
    if (!app.documents.length) {
        alert("Open a document", title, false);
        return;
    }
    doc = app.activeDocument;

    // DEFAULTS

    defaultSettings = {
        comma: true,
        semicolon: false,
        fileData: "",
        columnFind: "Find",
        columnChange: "Change"
    };

    // CREATE WORKING WINDOW

    working = new Window("palette", undefined, undefined, {
        closeButton: false
    });
    working.preferredSize = [300, 80];
    working.add("statictext");
    working.t = working.add("statictext");
    working.add("statictext");
    working.display = function (message) {
        this.t.text = message || "Working... Please wait...";
        this.show();
        this.update();
    };

    // CREATE USER INTERFACE

    w = new Window("dialog", title);
    w.alignChildren = "fill";
    // Panel 'Data file'
    p = w.add("panel", undefined, "Data file (CSV)");
    p.alignChildren = "left";
    p.margins = [18, 24, 18, 18];
    g = p.add("group");
    g.margins = [0, 0, 0, 4];
    g.add("statictext", undefined, "Delimiter:");
    g = g.add("group");
    g.margins = [0, 4, 0, 0];
    rbComma = g.add("radiobutton", undefined, "Comma");
    rbSemicolon = g.add("radiobutton", undefined, "Semicolon");
    g = p.add("group");
    btnFileData = g.add("button", undefined, "File...");
    txtFileData = g.add("statictext", undefined, "", {
        truncate: "middle"
    });
    txtFileData.preferredSize = [300, -1];
    // Group of 2 columns.
    g = p.add("group");
    g.margins = [0, 6, 0, 0];
    // Groups, columns 1 and 2.
    gc1 = g.add("group");
    gc1.orientation = "column";
    gc1.alignChildren = "left";
    gc2 = g.add("group");
    gc2.orientation = "column";
    gc2.alignChildren = "left";
    // Rows.
    gc1.add("statictext", undefined, "Column find:").preferredSize = [-1, 23];
    listColumnNames[0] = gc2.add("dropdownlist");
    listColumnNames[0].preferredSize = [150, 23];
    gc1.add("statictext", undefined, "Column change:").preferredSize = [-1, 23];
    listColumnNames[1] = gc2.add("dropdownlist");
    listColumnNames[1].preferredSize = [150, 23];
    // Panel
    p = w.add("panel");
    p.alignChildren = "left";
    p.margins = [18, 18, 18, 18];
    g = p.add("group");
    g.add("statictext", undefined, "Export current layer names");
    btnFileExport = g.add("button", undefined, "File...");
    // Action Buttons
    g = w.add("group");
    g.alignment = "center";
    btnOk = g.add("button", undefined, "OK");
    btnCancel = g.add("button", undefined, "Cancel");
    // Panel Copyright
    p = w.add("panel");
    p.add("statictext", undefined, "Copyright 2022 William Campbell");

    // SET DEFAULT VALUES / RESTORE LAST VALUES USED.
    // MUST PRECEDE UI EVENT HANDLERS SO THEY DON'T FIRE WHILE SETTING VALUES.

    rbComma.value = defaultSettings.comma;
    rbSemicolon.value = defaultSettings.semicolon;
    configureUi();

    // UI ELEMENT EVENT HANDLERS

    // Panel 'Data file'
    rbComma.onClick = clearFileData;
    rbSemicolon.onClick = clearFileData;
    btnFileData.onClick = function () {
        var cf;
        var f;
        var message;
        var setList;
        var validateFile;
        cf = new File(txtFileData.text);
        message = "Select CSV file";
        setList = function (uiList, prop) {
            uiList.selection = uiList.find(defaultSettings[prop]);
            uiList.priorIndex = uiList.selection !== null ? uiList.selection.index : null;
        };
        if (File.fs == "Macintosh") {
            validateFile = function (f) {
                if ((f instanceof Folder) || f.alias || /\.csv$/i.test(f.name)) {
                    return true;
                }
                return false;
            };
        } else {
            // Windows
            validateFile = "Comma Separated Values:*.csv";
        }
        if (cf.exists) {
            f = cf.openDlg(message, validateFile);
        } else {
            f = File.openDialog(message, validateFile);
        }
        if (f) {
            if (/\.csv$/i.test(f.name)) {
                message = readData(f);
                if (!message) { // Success
                    txtFileData.text = File.decode(f.fsName);
                    setList(listColumnNames[0], "columnFind");
                    setList(listColumnNames[1], "columnChange");
                }
            }
            if (message) { // Fail
                clearFileData();
                alert(message, " ", false);
            }
        }
    };
    // Export current layer names.
    btnFileExport.onClick = function () {
        var file;
        var i;
        var encodeCsv = function (v) {
            var s = String(v);
            if (/[,\"]/.test(s)) {
                // Escape quotation marks.
                s = s.replace(/"/g, "\"\"");
                // Wrap in quotation marks.
                s = "\"" + s + "\"";
            }
            return s;
        };
        file = File.saveDialog("Export current layer names", "Comma Separated Values:*.csv");
        if (file) {
            file.encoding = "UTF-8";
            file.open("w");
            file.writeln("Find,Change");
            for (i = 0; i < doc.layers.length; i++) {
                file.writeln(encodeCsv(doc.layers[i].name) + ",");
            }
            file.close();
            alert("Current layers exported", title, false);
        }
    };
    // Action Buttons
    btnOk.onClick = function () {
        if (!(dataArray && dataArray.length)) {
            alert("Select CSV file", " ", false);
            return;
        }
        if (!listColumnNames[0].selection) {
            alert("Select column find", " ", false);
            return;
        }
        if (!listColumnNames[1].selection) {
            alert("Select column change", " ", false);
            return;
        }
        w.close(1);
    };
    btnCancel.onClick = function () {
        w.close(0);
    };

    // DISPLAY THE DIALOG

    if (w.show() == 1) {
        doneMessage = "";
        try {
            if (/InDesign/.test(app.name)) {
                app.doScript(process, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, title);
            } else {
                // Illustrator
                process();
            }
            doneMessage = "Done";
        } catch (e) {
            error = error || e;
            doneMessage = "An error has occurred." + "\n" + "Line" + " " + error.line + ": " + error.message;
        }
        working.close();
        doneMessage && alert(doneMessage, title, error);
    }

    //====================================================================
    //               END PROGRAM EXECUTION, BEGIN FUNCTIONS
    //====================================================================

    function clearFileData() {
        var i;
        txtFileData.text = "";
        for (i = 0; i < listColumnNames.length; i++) {
            listColumnNames[i].removeAll();
        }
    }

    function configureUi() {
        if (!(rbComma.value || rbSemicolon.value)) {
            rbComma.value = true;
        }
    }

    function parseCsv(data, delimiter) {
        // data: String = contents of a CSV file
        // delimiter: character that separates columns
        //            undefined defaults to comma
        // Returns: Array [[String row, String column]]
        var c = ""; // Character at index.
        var d = delimiter || ","; // Default to comma.
        var endIndex = data.length;
        var index = 0;
        var maxIndex = endIndex - 1;
        var q = false; // "Are we in quotes?"
        var result = []; // Array of rows (array of column arrays).
        var row = []; // Array of columns.
        var v = ""; // Column value.
        while (index < endIndex) {
            c = data[index];
            if (q) { // In quotes.
                if (c == "\"") {
                    // Found quote; look ahead for another.
                    if (index < maxIndex && data[index + 1] == "\"") {
                        // Found another quote means escaped.
                        // Increment and add to column value.
                        index++;
                        v += c;
                    } else {
                        // Next character not a quote; last quote not escaped.
                        q = !q; // Toggle "Are we in quotes?"
                    }
                } else {
                    // Add character to column value.
                    v += c;
                }
            } else { // Not in quotes.
                if (c == "\"") {
                    // Found quote.
                    q = !q; // Toggle "Are we in quotes?"
                } else if (c == "\n" || c == "\r") {
                    // Reached end of line.
                    // Test for CRLF.
                    if (c == "\r" && index < maxIndex) {
                        if (data[index + 1] == "\n") {
                            // Skip trailing newline.
                            index++;
                        }
                    }
                    // Column and row complete.
                    row.push(v);
                    v = "";
                    // Add row to result if first row or length matches first row.
                    if (result.length == 0 || row.length == result[0].length) {
                        result.push(row);
                    }
                    row = [];
                } else if (c == d) {
                    // Found comma; column complete.
                    row.push(v);
                    v = "";
                } else {
                    // Add character to column value.
                    v += c;
                }
            }
            if (index == maxIndex) {
                // Reached end of data; flush.
                if (v.length || c == d) {
                    row.push(v);
                }
                // Add row to result if length matches first row.
                if (row.length == result[0].length) {
                    result.push(row);
                }
                break;
            }
            index++;
        }
        return result;
    }

    function process() {
        var change;
        var find;
        var i;
        var ii;
        var layer;
        working.display();
        if (/InDesign/.test(app.name)) {
            app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;
        } else {
            // Illustrator
            // eslint-disable-next-line no-undef
            app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
        }
        try {
            // Get column indexes.
            for (i = 0; i < listColumnNames.length; i++) {
                if (listColumnNames[i].selection) {
                    columnIndex[i] = listColumnNames[i].selection.index;
                }
            }
            // Build find/change arrays.
            for (i = 0; i < dataArray.length; i++) {
                find = dataArray[i][columnIndex[0]];
                change = dataArray[i][columnIndex[1]];
                if (find && change) {
                    finds.push(find);
                    changes.push(change);
                }
            }
            // Go.
            // Perform find/change.
            for (i = 0; i < finds.length; i++) {
                for (ii = 0; ii < doc.layers.length; ii++) {
                    layer = doc.layers[ii];
                    if (layer.name == finds[i]) {
                        layer.name = changes[i];
                    }
                }
            }
        } catch (e) {
            error = e;
            throw e;
        } finally {
            // Restore preferences.
            if (/InDesign/.test(app.name)) {
                app.scriptPreferences.userInteractionLevel = UserInteractionLevels.INTERACT_WITH_ALL;
            } else {
                // Illustrator
                // eslint-disable-next-line no-undef
                app.userInteractionLevel = UserInteractionLevel.DISPLAYALERTS;
            }
        }
    }

    function readData(file) {
        var data;
        var header = [];
        var i;
        var ii;
        var item;
        var list;
        var selected;
        if (file.length > 100000) {
            return "Data file size exceeds 100K maximum";
        }
        // Read data file.
        if (!file.open("r")) {
            return "Failed to open data file";
        }
        try {
            data = file.read();
        } catch (e) {
            return "Error reading data file" + ": " + e.message;
        } finally {
            file.close();
        }
        // Parse data file.
        dataArray = parseCsv(data, rbSemicolon.value ? ";" : ",");
        // Two rows minimum.
        if (dataArray.length < 2) {
            return "Data file missing rows";
        }
        // Extract header row.
        header = dataArray.shift();
        // Two columns minimum.
        if (!header || header.length < 2) {
            return "Data file missing columns";
        }
        // Set drop-down lists to data headers.
        for (i = 0; i < listColumnNames.length; i++) {
            list = listColumnNames[i];
            selected = list.selection ? list.selection.text : "";
            list.removeAll();
            for (ii = 0; ii < header.length; ii++) {
                if (header[ii]) {
                    item = list.add("item", header[ii]);
                    if (item.text == selected) {
                        list.selection = item;
                    }
                }
            }
        }
        return null; // Success
    }

})();
Many scripts are free to download thanks to the support of users. Help me keep developing new scripts by supporting my work. Click the button to make a contribution of any amount. Thank you.
Download
Layers Rename From CSV

For help installing scripts, see How to Install and Use Scripts in Adobe Creative Cloud Applications.

Also available for hire to program custom solutions. Contact William for more information.

IMPORTANT: by downloading any of the scripts on this page you agree that the software is provided without any warranty, express or implied. USE AT YOUR OWN RISK. Always make backups of important data.