Copy link to clipboard
Copied
I have a table that I scan and sort into 2 different arrays. The first array is a part name the second array is a part number.
What I am trying to accomplish is adding the part number in front of the part name when it finds a match. However I think my loop to compare is wrong. Could someone take a look and advise of a more efficient loop to compare?
for (var i = 0; i < allText.length; i++) {
for (var ii = 0; ii < allText.length; ii++){
if (allText.contents == componentName[ii]){
allText.contents = "(" + componentCallout[ii] + ") " + allText.contents;
}
}
}
I need to scan the entire document and find if any text frame matches the text from my array
componentName
The code you see works on a small scale but when I try to use it on a document with a lot of text it just crunches and crunches.
Anyone see a more efficient way to loop this?
Thanks!
switching them back worked here too.
Good catch on the -1 to bring the callout back to the correct name (even though by fixing the error that is fixed too and not needed)
as for it picking up the other values you marked above, glaring error in code!
it is finding a match for C2, for example, as C2 pops up in something like RLY_WKTL_C2.
answer is to make sure it matches the whole name.
should be worth noting that if any componentName contains a tilde '~' the script will fall on its face.
This has now d
...Copy link to clipboard
Copied
my first thought is to break; if match is found so it does not keep checking once it has found its match.
not sure if a regexp would be faster or not.
but I think the best bet would be to do something like:
for (var i=0; i < allText.length; i++){
if(componentName.indexOf(allText.contents)>-1){
var componentIndex = componentName.indexOf(allText.contents);
allText.contents = "(" + conmponentCallout[componentIndex] + ")" + allText.contents;
}
}
the above has not been tested at all!
it may be even faster if you used a 2 dimensional array... Maybe...
Copy link to clipboard
Copied
When I run this block of code:
for (var i=0; i < allText.length; i++){
if(componentName.indexOf(allText.contents)>-1){
var componentIndex = componentName.indexOf(allText.contents);
allText.contents = "(" + conmponentCallout[componentIndex] + ")" + allText.contents;
}
}
I get an error message that componentName.indexOf is not a function.
Here is my entire code (with your addition) if that helps:
#target illustrator
var doc = app.activeDocument;
var allLayers = doc.layers;
var allText = doc.textFrames;
var componentName = [];
var componentCallout = [];
var z = 1;
var j = 0;
for (var i = 0; i < allText.length; i++) {
if (allText.layer == "[Layer Table]") {
if (j <= allText.length){
componentCallout.push(allText
.contents); j+=2;
}
else if (z <= allText.length){
componentName.push(allText
.contents); z+=2;
}
}
}
for (var i=0; i < allText.length; i++){
if(componentName.indexOf(allText.contents)>-1){
var componentIndex = componentName.indexOf(allText.contents);
allText.contents = "(" + conmponentCallout[componentIndex] + ")" + allText.contents;
}
}
Copy link to clipboard
Copied
AS I said. Has not been tested at all.
i‌ prob got some syntax wrong.
ill have a play and get back to you
Copy link to clipboard
Copied
sorry, illustrator does not have indexOf as a function of arrays, normal javascript does.
here is a workaround I got to work in a test situation.
Re-worded to suit your code.
let me know if it fails.
Let me know if it work and if it does give you better speed.
var componentString = "~" + componentName.join("~");
for (var i=0; i < allText.length; i++){
var componentIndex = componentString.substr(0,componentString.indexOf(allText.contents)).match(new RegExp(/~/g)).length;
if(componentIndex > -1){
allText.contents = "(" + conmponentCallout[componentIndex] + ")" + allText.contents;
}
}
Copy link to clipboard
Copied
I get an error:
null is not an object
on the following line....
var componentIndex = componentString.substr(0,componentString.indexOf(allText.contents)).match(new RegExp(/~/g)).length;
Copy link to clipboard
Copied
Tables? Or text frames? Part numbers? Part names?
Please show us a little bit more. E.g. screenshots before and after. Or an example file (cs3-compatible - my own version) or at max CS5
Copy link to clipboard
Copied
Here are 2 example files. Keep in mind I had to make a lot of the information generic so the text that says Description Info won't actually have that content in the normal file. Same thing applies to the text that says 111-A222 BB-14.
So to improve the speed I have changed the code a little. I open my main file then I open the table info file. I run the code with the table file as the active document.
Here is a link to 2 sample files (open GENERIC.pdf file first then open Table Data.pdf). Then here is my most recent code:
#target illustrator
var doc = app.activeDocument;
var allText = doc.textFrames;
var componentName = [];
var componentCallout = [];
var z = 1;
var j = 0;
for (var i = 0; i < allText.length; i++) {
if (j < allText.length) {
//alert(allText
.contents); componentCallout.push(allText
.contents); j += 2;
}
if (z < allText.length) {
//alert(allText
.contents); componentName.push(allText
.contents); z += 2;
}
}
doc.close(SaveOptions.DONOTSAVECHANGES);
alert("Table scanned");
var doc = app.activeDocument;
var allText = doc.textFrames;
var allText = doc.textFrames;
for (var i = 0; i < allText.length; i++) {
for (var ii = 0; ii < allText.length; ii++) {
if (allText.contents == componentName[ii]) {
allText.contents = "(" + componentCallout[ii] + ") " + allText.contents;
break;
}
}
}
alert("Done");
I am working with Illustrator CS4
Copy link to clipboard
Copied
Hi subieguy2‌,
thanx for sending your sample files – but sorry this was vainly.
A PDF file converted between different version will always break the text frames. Could you send the Table Date file files again, please? (saved as CS3 compatible AI file)
Your Generic.pdf seems to be ok.
Copy link to clipboard
Copied
pixxxel schubser‌ Thank you for pointing that out. Didn't think about it breaking the text frames.
I have uploaded .ai CS3 compatible to the same location as above.
https://www.dropbox.com/sh/tho3yj78mvseqbz/AABxdTGH1H_oUCTvgT4HgklIa?dl=0
Copy link to clipboard
Copied
the files helped.
there was a spelling mistake in line 5 of my snippet "conmponent" oops.
the "null" error was due to an incorrect test if value existed in the array.
also the two arrays got reversed...
here is your code back, with a completely inaccurate timer.
on my machine it runs just over 5 seconds. I am on CC2015 with a fairly decent machine.
fingers crossed it runs ok in CS4
I'm sure it will be fine....
#target illustrator
var start = new Date().getTime();
var doc = app.activeDocument;
var allText = doc.textFrames;
var componentName = [];
var componentCallout = [];
var z = 1;
var j = 0;
for (var i = 0; i < allText.length; i++) {
if (j < allText.length) {
//alert(allText
.contents); componentCallout.push(allText
.contents); j += 2;
}
if (z < allText.length) {
//alert(allText
.contents); componentName.push(allText
.contents); z += 2;
}
}
doc.close(SaveOptions.DONOTSAVECHANGES);
//alert("Table scanned");
var doc = app.activeDocument;
var allText = doc.textFrames;
var allText = doc.textFrames;
var componentString = "~" + componentCallout.join("~");
for (var i=0; i < allText.length; i++){
if(componentString.indexOf(allText.contents) > -1){
var componentIndex = componentString.substr(0,componentString.indexOf(allText.contents)).match(new RegExp(/~/g)).length;
allText.contents = "(" + allText.contents + ")" + componentName[componentIndex];
}
}
//alert("Done");
var end = new Date().getTime();
var time = (end - start)/1000;
alert('Execution time: ' + time + ' seconds');
Copy link to clipboard
Copied
Ok first of all thank you so much for taking the time you have on this! I appreciate it so much!
I ran your code and my machine took about 9 seconds to run it. This is an amazing difference from what I originally started with.
However the code isn't doing exactly what I need it to.
If you look at the table information column 1 is the component name. The component name is what needs to be searched for on the generic document. So to better explain myself I will use a specific example.
When the first part of the code runs it stores column 1 in the componentName array and column 2 in the componentCallout.
componentName componentCallout
Then on the generic.ai file it will search for the content of the componentName array....in this example:
CONT_GP_JSTICK_RH
When a match for CONT_GP_JSTICK_RH is found it will change the original content:
To the following format shown in red (24) CONT_GP_JSTICK_RH
Nothing else will change. Just find a match from the componentName array and add the componentCallout number to the front of it with parentheses around the number.
Sorry I don't mean to be a pain....again I appreciate all your efforts. My script takes over 30 minutes to run and sometimes crashes Illustrator. So when you come up with something that takes 9 SECONDS!! that floors me. Any help to get the code to do this in that fast would help me tremendously!
Thanks again and I look forward to your response!
Copy link to clipboard
Copied
so the arrays not the wrong way around.
this should be an easy fix.
bit too late now. will do this tomorrow...
Copy link to clipboard
Copied
Ok based on what you said I flipped the arrays around. The code runs great!!
#target illustrator
var start = new Date().getTime();
var doc = app.activeDocument;
var allText = doc.textFrames;
var componentName = [];
var componentCallout = [];
var z = 1;
var j = 0;
for (var i = 0; i < allText.length; i++) {
if (j < allText.length) {
//alert(allText
.contents); componentCallout.push(allText
.contents); j += 2;
}
if (z < allText.length) {
//alert(allText
.contents); componentName.push(allText
.contents); z += 2;
}
}
doc.close(SaveOptions.DONOTSAVECHANGES);
var doc = app.activeDocument;
var allText = doc.textFrames;
var componentString = "~" + componentName.join("~");
for (var i = 0; i < allText.length; i++) {
if (componentString.indexOf(allText.contents) > -1) {
var componentIndex = componentString.substr(0, componentString.indexOf(allText.contents)).match(new RegExp(/~/g)).length;
allText.contents = "(" + componentCallout[(componentIndex - 1)] + ") " + allText.contents;
}
}
var end = new Date().getTime();
var time = (end - start) / 1000;
alert('Execution time: ' + time + ' seconds');
The only small issue I see when the code runs is that it is picking up some random stuff that don't match the componentName string.
See the items in red....those shouldn't be changing. Any thoughts?
Before Code:
After Code:
is it also possible to move the textFrames that are changed to a layer called "Formatted" ?
Copy link to clipboard
Copied
switching them back worked here too.
Good catch on the -1 to bring the callout back to the correct name (even though by fixing the error that is fixed too and not needed)
as for it picking up the other values you marked above, glaring error in code!
it is finding a match for C2, for example, as C2 pops up in something like RLY_WKTL_C2.
answer is to make sure it matches the whole name.
should be worth noting that if any componentName contains a tilde '~' the script will fall on its face.
This has now decided to consistently run under 2.5 seconds...
Give this a go...
#target illustrator
var start = new Date().getTime();
var doc = app.activeDocument;
var allText = doc.textFrames;
var componentName = [];
var componentCallout = [];
var z = 1;
var j = 0;
var count = 0;
for (var i = 0; i < allText.length; i++) {
if (j < allText.length) {
//alert(allText
.contents); componentCallout.push(allText
.contents); j += 2;
}
if (z < allText.length) {
//alert(allText
.contents); componentName.push(allText
.contents); z += 2;
}
}
doc.close(SaveOptions.DONOTSAVECHANGES);
//alert("Table scanned");
var doc = app.activeDocument;
var allText = doc.textFrames;
//create new layer for affected text
try{
var lay = doc.layers.getByName("modified");
}catch(e){
var lay = doc.layers.add();
lay.name = "modified";
}
var allText = doc.textFrames;
var componentString = "~" + componentName.join("~") + "~";
for (var i=allText.length-1; i >0 ; i--){
if(componentString.indexOf("~" + allText.contents + "~") > 0){
var componentIndex = componentString.substr(0,componentString.indexOf("~" + allText.contents + "~")).match(new RegExp(/~/g)).length;
allText.contents = "(" + componentCallout[componentIndex] + ")" + allText.contents;
allText.move(lay, ElementPlacement.PLACEATBEGINNING);
count++
}
}
//alert("Done");
var end = new Date().getTime();
var time = (end - start)/1000;
alert('Execution time: ' + time + ' seconds\nTotal textFrames tested: ' + allText.length + '\nNumber of affected textFrames: ' + count);
Copy link to clipboard
Copied
Qwertyfly... You are the man! Thank you for sticking with this!!! I do similar searches on a day to day basis. Learned a lot from your code! MUCH APPRECIATED!!!
Copy link to clipboard
Copied
Glad I could help.
the reason I'm here is to learn new ways to do things, and expand my ideas on how I can improve my own workflow.
every time I help someone with a more in depth solution such as this I learn something new.
glad I could help out and hope the code serves you well.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now