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

Changing font of specific words in a text range using an array

Community Beginner ,
May 21, 2023 May 21, 2023

Copy link to clipboard

Copied

Hi,

In a selected Illustrator area text object, I'd like to put all allergens of an ingredient list in a bold font.

 

Example ingredients list:

Ingredients: sausage 34% (pork 67%, water, potato starch, pork bacon, salt, soy protein, spices (contains mustard), herbs (contains celery), milk protein, emulsifier (triphosphates), antioxidants (sodium ascorbate, monosodium glutamate), preservative (sodium nitrite)).

 

My allergens array: 

allergenList = ["soy", "mustard", "celery", "milk"]
 
(part of) my script:
var ingredientList = doc.selection[0].textRange;
 
var i = 0;
for (i=0; i < ingredientList.words.length; i++){
var wordSelected = ingredientList.words[i];
//checking matches between ingredientList and allergenList
var k = 0;
for (k=0; k < allergenList.length; k++){
if (wordSelected.contents == allergenList[k]){
// formatting the selection
wordSelected.characterAttributes.textFont = textFonts.getByName("MyriadPro-BoldCond")
break;
}
}
}
 
But it appears the .word subrange is not the ideal approach: when an allergen word is followed by a parenthese, it is not correctly selected. As a matter of fact, the .contents returns a word without the last letter (e.g. 'celer' instead of 'celery')
 
I am sure there are better and smarter approaches but I am a newby to AI scripting 🙂
 
Also, I think it would be wiser to load the allegens list from a text file rather than a hard-coded array, but that is another challenge to tackle.
 
Me and all food sensitive people will be very grateful for your help:)
TOPICS
Scripting

Views

676

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

correct answers 1 Correct answer

Guide , Jun 06, 2023 Jun 06, 2023

You can refine the logic defining a "word" so it is preceded by a space and followed by a space, comma or full stop. 

// select text frame
var array = ["soy", "mustard", "celery", "milk"];
var string = app.selection[0].contents;
var indices = [];

for (var i = 0; i < array.length; i++) {
    indices = indices.concat(getIndices(array[i]));
}

for (var i = 0; i < indices.length; i++) {
    if (string[indices[i]._1st - 1] == " " && 
        (string[indices[i]._nth] == " " || 
         string[indices
...

Votes

Translate

Translate
Adobe
Guide ,
May 21, 2023 May 21, 2023

Copy link to clipboard

Copied

I am sure there are better ways, but this is what popped into my head.  It won't do repeated words though. 

// select text frame
var array = ["soy", "mustard", "celery", "milk"];
var string = app.selection[0].contents;
for (var i = 0; i < array.length; i++) {
    var firstChar = string.search(array[i]);
    var lastChar = firstChar + array[i].length;
    for (var j = firstChar; j < lastChar; j++) {
        var attributes = app.selection[0].textRanges[j].characterAttributes;
        attributes.textFont = textFonts["MyriadPro-BoldCond"];
    }
}

 

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 ,
May 22, 2023 May 22, 2023

Copy link to clipboard

Copied

Hi femkeblanco, thanks a lot for taking timing to look into my challenge. This indeed is a smart approach, but some words do repeat a lot (like 'milk' or 'soy').

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
Guide ,
May 22, 2023 May 22, 2023

Copy link to clipboard

Copied

Sticking with the same idea, this should do repeated words.

// select text frame
var array = ["soy", "mustard", "celery", "milk"];
var string = app.selection[0].contents;
var indices = [];

for (var i = 0; i < array.length; i++) {
    indices = indices.concat(getIndices(array[i]));
}

for (var i = 0; i < indices.length; i++) {
    for (var j = indices[i]._1st; j < indices[i]._nth; j++) {
        var attributes = app.selection[0].textRanges[j].characterAttributes;
        attributes.textFont = textFonts["MyriadPro-BoldCond"];
    }
}

function getIndices(substring) {
    var indices = [];
    var index = string.indexOf(substring);
    while (index != -1) {
        indices.push({_1st: index, _nth: index + substring.length});
        index = string.indexOf(substring, index + 1);
    }
    return indices;
}

 

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 ,
May 22, 2023 May 22, 2023

Copy link to clipboard

Copied

Thank you so much, this works great!

 

Now there is one more issue which is quite complex, and I suppose this goes beyond the purpose of this support community?

 

But it is, when an allergen is specified (by its ingredients between parentheses), the allergen itself is not put in bold, but only the component that is the 'real' allergen.

 

To illustrate the possible situations:

• pork bacon, salt, soy protein -> pork bacon, salt, soy protein > ok!

• spices (contains mustard) -> spices (contains mustard) > ok!

but:

• mustard 9 % (mustard 77 % (vinegar, mustard seed, salt, curcuma), dextrose, corn starch) -> mustard 9 % (mustard 77 % (vinegar, mustard seed, salt, curcuma), dextrose, corn starch)

 

It seems very complex to me to code this sort of 'human' reasoning, as it has to take into account the context, that is, the appearence of (one or more) parentheses after a possible match. And also, I think I should be paying you by now for such amount of magnificent support 🙂

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
Guide ,
May 22, 2023 May 22, 2023

Copy link to clipboard

Copied

My immediate impression is that you need to

 

(1) parse the parenthesised string into a nested array; and
(2) recursively iterate the nested array, getting the matches if they are not in succeeding inner arrays.

 

I can do (1), but I'm unsure how to do (2). If I have the time, I'll try to think about it in the next couple of days. Hopefully, someone else might think of something I haven't.

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 ,
Jun 04, 2023 Jun 04, 2023

Copy link to clipboard

Copied

Hello Femke,

 

in the above script, would it be possible to only check on whole words to but in bold? So that 'mustard' is put in bold, but not 'mustardflavour' ?

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
Guide ,
Jun 04, 2023 Jun 04, 2023

Copy link to clipboard

Copied

The above code manipultes strings; it does not recognise words.  But you can add your own logic to define a "word".  So you can add a conditional that boldens a substring only if it is followed by a space, comma or full stop. 

// select text frame
var array = ["soy", "mustard", "celery", "milk"];
var string = app.selection[0].contents;
var indices = [];

for (var i = 0; i < array.length; i++) {
    indices = indices.concat(getIndices(array[i]));
}

for (var i = 0; i < indices.length; i++) {
    if (string[indices[i]._nth] == " " || 
        string[indices[i]._nth] == "," ||
        string[indices[i]._nth] == ".") {
        for (var j = indices[i]._1st; j < indices[i]._nth; j++) {
            var attributes = app.selection[0].textRanges[j].characterAttributes;
            attributes.textFont = textFonts["MyriadPro-BoldCond"];
        }
    }
}

function getIndices(substring) {
    var indices = [];
    var index = string.indexOf(substring);
    while (index != -1) {
        indices.push({_1st: index, _nth: index + substring.length});
        index = string.indexOf(substring, index + 1);
    }
    return indices;
}

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 ,
Jun 06, 2023 Jun 06, 2023

Copy link to clipboard

Copied

Hello Femke, thank you so much! Now it only still puts words in bold that contain an allergen word (like chicken legg > chicken legg). I tried to identify the character (space, comma,...) before each word by using index-1, but it doesn't seem to work. Or is it possible to check if both words have the same lenght and add this as a condition for putting in bold?

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
Guide ,
Jun 06, 2023 Jun 06, 2023

Copy link to clipboard

Copied

You can refine the logic defining a "word" so it is preceded by a space and followed by a space, comma or full stop. 

// select text frame
var array = ["soy", "mustard", "celery", "milk"];
var string = app.selection[0].contents;
var indices = [];

for (var i = 0; i < array.length; i++) {
    indices = indices.concat(getIndices(array[i]));
}

for (var i = 0; i < indices.length; i++) {
    if (string[indices[i]._1st - 1] == " " && 
        (string[indices[i]._nth] == " " || 
         string[indices[i]._nth] == "," ||
         string[indices[i]._nth] == ".")) {
        for (var j = indices[i]._1st; j < indices[i]._nth; j++) {
            var attributes = app.selection[0].textRanges[j].characterAttributes;
            attributes.textFont = textFonts["MyriadPro-BoldCond"];
        }
    }
}

function getIndices(substring) {
    var indices = [];
    var index = string.indexOf(substring);
    while (index != -1) {
        indices.push({_1st: index, _nth: index + substring.length});
        index = string.indexOf(substring, index + 1);
    }
    return indices;
}

 

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 ,
Jun 08, 2023 Jun 08, 2023

Copy link to clipboard

Copied

LATEST

Hi Femke, great, this is my solution! I added some extra characters:

 

for (var i = 0; i < indices.length; i++) {

   if ((string[indices[i]._1st - 1] == "(" ||
        string[indices[i]._1st - 1] == " " ) &&
         
        (string[indices[i]._nth] == " " || 
         string[indices[i]._nth] == "," ||
         string[indices[i]._nth] == ")" ||
         string[indices[i]._nth] == ".")) {
        for (var j = indices[i]._1st; j < indices[i]._nth; j++) {
            var attributes = app.selection[0].textRanges[j].characterAttributes;
            attributes.textFont = textFonts["MyriadPro-BoldCond"];
        }
    }    
}

 Many more functions to add still and so much to learn and explore, but this was very helpful and educational, thanks again!

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 ,
May 22, 2023 May 22, 2023

Copy link to clipboard

Copied

Such things can be achieved with regular expressions. The following tools seem to work in Illustrator.

 

 

All explanations are written in Japanese, but please use a translation tool to read them.

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