how to create a list of text(String) and use it in illustrator script.

New Here ,
May 07, 2022 May 07, 2022

Copy link to clipboard

Copied

Hello, I would like to find/replace words. For that i am trying to create a list of words(for as many as I have) and then use them in the script in a loop. so, I modified the script but can't figure out how to make it work my way. 

*so the parts of the initial script are this (which is working):

layers = app.activeDocument.layers

var config = {

targets: [

{


find: "textA",

replace:"TextB",

.

.

.

frame.contents = frame.contents.replace(target.find, target.replace);

 

*I modified to smth like this:

layers = app.activeDocument.layers

var config = {

targets: [

{


find: [],

replace:[],

 

find[0]:"TextA1"

replace[0]:"TextB1"

find[1]:"TextA2"

replace[1]:"TextB2"

.

.

.

for (var i=0;i<=1;i++){

frame.contents = frame.contents.replace(target.find[i], target.replace[i]);

}

I am really stuck in this issue. Thank you in advance for your usual help.

 

 

TOPICS
Scripting

Views

145

Likes

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
Adobe Community Professional ,
May 07, 2022 May 07, 2022

Copy link to clipboard

Copied

Hi @Amine241660526qdd, first of all well done for getting your script to this point! 🙂

When you ask a question about a specific script you really need to post the complete script that is failing (can be a simplified script that highlights the problem) or at least complete pseudo-code. From what you have posted I have no idea if your script has faulty syntax or if your syntax is fine but you are going about things the wrong way—what you have posted certainly won't work—even the one that you say works, because it is incomplete.

 

Best I can do without more information from you is show a working possible solution:

var doc = app.activeDocument,
    items = doc.selection;

var textReplacements = [
    { findWhat: 'TextA1', changeTo: 'TextB1' },
    { findWhat: 'TextA2', changeTo: 'TextB2' },
    { findWhat: 'TextA3', changeTo: 'TextB3' }
];

// loop over items
for (var i = 0; i < items.length; i++) {
    var item = items[i];
    // only perform find if item has 'contents'
    if (item.hasOwnProperty('contents')) {
        // loop over textReplacements for each frame
        for (var j = 0; j < textReplacements.length; j++) {
            item.contents = item.contents.replace(textReplacements[j].findWhat, textReplacements[j].changeTo);
        }
    }
}

 

Does that help? Otherwise it would be good to post some actual code that is failing. Feel free to ask questions.

- Mark

 

P.S. Did you notice I changed some of the variable names? I always try to make them accurate, readable and fairly precise. I changed "targets" to "textReplacements" because the replacement "TextB1" is not a target. Your use of "find" and "replace" were perfectly fine—I only changed them to match my personal choice (actually because it matches Indesign's find change API properties "findWhat" and "changeTo").

 

Likes

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
Advocate ,
May 07, 2022 May 07, 2022

Copy link to clipboard

Copied

Context and details are missing. But it looks like you're trying to write something like this

 

var frame = app.activeDocument.textFrames[0];
var config = {
    targets: [
        {find: "textA1", replace: "textB1"},
        {find: "textA2", replace: "textB2"}
    ]
};
for (var i = 0; i < config.targets.length; i++) {
    frame.contents = frame.contents.replace(config.targets[i].find, config.targets[i].replace);
}

Edit:  @m1b beats me to it again while I am typing. 

 

Likes

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
Adobe Community Professional ,
May 07, 2022 May 07, 2022

Copy link to clipboard

Copied

Haha, sorry! Yes we never know if someone is already answering.

But I suppose having too much help is not a bad problem to have.  🙂

Likes

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
Adobe Community Professional ,
May 07, 2022 May 07, 2022

Copy link to clipboard

Copied

How about with a third way:

Multiple Line Replace Script? 

 

(The longer the list of words, the more likely I would go that way.)

Likes

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
Adobe Community Professional ,
May 08, 2022 May 08, 2022

Copy link to clipboard

Copied

Yes definitely agree this is a good way to go with many pairs. Good point.

Likes

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
New Here ,
May 07, 2022 May 07, 2022

Copy link to clipboard

Copied

Hello all, thank you for taking the time to help.

 

I did not paste the whole script because I thought it was too long.

I did this and it worked:

 

find: ["TextA1", "TextA2", "TextA3"],
replace: ["TextB1", "TextAB2", "TextB3"],

.

.

.

for (var i=0;i<=1;i++){

frame.contents = frame.contents.replace(target.find[i], target.replace[i]);

}

 

Thank you all again.

Likes

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
Adobe Community Professional ,
May 07, 2022 May 07, 2022

Copy link to clipboard

Copied

Glad you got it working. The reason we paired the find and replace strings is that it is easier, if the list is long, to know and specify the corresponding pair.

- Mark

Likes

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
Enthusiast ,
May 08, 2022 May 08, 2022

Copy link to clipboard

Copied

This looks like it might be one of my own scripts:

 

var config = {
  // Support for any amount of find/replace parameters here
  targets: [
    {
      find: "foo",
      replace: "bar",
    },
    {
      find: /(locked|hidden)/i, // including support for Regex patterns
      replace: "Success",
    },
  ],
  affects: {
    // names: false, // Whether it changes names, not implemented but possible
    content: true, // Must be true at this basic state of the script
  },
  searchIn: {
    hidden: false, // Whether it changes hidden layer contents
    locked: true, // Whether it changes locked layer contents
  },
};
//
// Don't alter the below unless you know what you're doing.
//
// Very simple ES6 polyfills for Array methods to make code more concise:
Array.prototype.filter = function (callback) {
  var filtered = [];
  for (var i = 0; i < this.length; i++)
    if (callback(this[i], i, this)) filtered.push(this[i]);
  return filtered;
};
Array.prototype.forEach = function (callback) {
  for (var i = 0; i < this.length; i++) callback(this[i], i, this);
};
// This is a bit too verbose for what we need here, but as-is can recurse to find sublayers no matter the depth if we use:
// var list = get("layers"); <-- This is *all* layers and sublayers, not just the root-level / depth 0 ones from doc.layers.
function get(type, parent, deep) {
  if (arguments.length == 1 || !parent) {
    parent = app.activeDocument;
    deep = true;
  }
  var result = [];
  if (!parent[type]) return [];
  for (var i = 0; i < parent[type].length; i++) {
    result.push(parent[type][i]);
    if (parent[type][i][type] && deep)
      result = [].concat(result, get(type, parent[type][i], deep));
  }
  return result;
}

// The main obstacle is getting a recursive parent chain, then determining if any part of this chain doesn't meet requirements:
function checkAncestry(frame) {
  // So we'll split the logic into just constructing a recursive Array containing data about parents when applicable:
  function getAncestry(frame) {
    // And have a dedicated recursive function to look into the parent then recurse and concat an Array when needed:
    function getParentChain(item, data) {
      if (item.parent && /layer/i.test(item.parent.typename))
        data = getParentChain(
          item.parent,
          [].concat(
            { hidden: !item.parent.visible, locked: item.parent.locked },
            data
          )
        );
      return data;
    }
    // For ease, we start the chain with the textFrame's hidden/locked data:
    return getParentChain(frame, [
      { hidden: frame.hidden, locked: frame.locked },
    ]);
  }
  // Now that we have a list like [ { locked: true, hidden: false }, {locked: false, hidden: false }, ... ]
  // We can filter it to see if there are any hidden/lockeds present:
  var chain = getAncestry(frame),
    hiddenStatus =
      chain.filter(function (i) {
        return i.hidden;
      }).length > 0,
    lockedStatus =
      chain.filter(function (i) {
        return i.locked;
      }).length > 0;
  // AI doesn't handle short circuiting well, so if no locked/hiddens exist, we'll explicitly return:
  if (!lockedStatus && !hiddenStatus) return true;
  // Otherwise we need to ensure the chain contents either match the queries or returned empty:
  else
    return (
      (hiddenStatus == config.searchIn.hidden || !hiddenStatus) &&
      (lockedStatus == config.searchIn.locked || !lockedStatus)
    );
}

// Our main function can now be very concise, we get all text frames:
get("textFrames")
  // But remove any that don't match our search queries for hidden/locked
  .filter(function (i) {
    return checkAncestry(i);
    // Then for every remaining textFrame:
  })
  .forEach(function (frame) {
    // And for every find/replace option:
    config.targets.forEach(function (target) {
      // Replace the text content of the frame:
      frame.contents = frame.contents.replace(target.find, target.replace);
    });
  });

I don't mind modifying this to do what you want, but it's not really explained here how the above script isn't satisfactory. If you have a list of words and you want to replace any of this list with the same word, you could keep everything in this script and just create a single regex entry:

 

    {
      // A list like alpha, beta, delta, gamma replaced by epsilon:
      find: /(alpha|beta|delta|gamma)/i, // including support for Regex patterns
      replace: "epsilon",
    },

 

Likes

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
Enthusiast ,
May 08, 2022 May 08, 2022

Copy link to clipboard

Copied

LATEST

As a followup the reason this script is so long is because the original thread was specifically about find/replace only during certain conditions -- only if the text frame had no hidden/locked ancestor regardless of depth. So it is long compared to basic find/replace methods but this is more from specific request than necessity, and when you're googling find/replace scripts, it's probably best to ignore ones like this where they have context or needs that are far more complicated than your own.

Likes

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