Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Forums Adobe After Effects Expressions Text from array layer to text layer depending on text in a third text layer

  • Text from array layer to text layer depending on text in a third text layer

  • Philip Peterson

    March 2, 2021 at 3:56 pm

    Another day of diving deeper into After Effects expressions and another hurdle in front of me:

    So I have 3 text layers:

    A = text layer consisting of many (double) names & (double) surnames, some with a number if the names are the same, each name is separated by a comma (copied over from an excel sheet).

    B = text layer that is used as an input for names.

    C = text layer that is showing matching names and changes characters that match to bold while the input in B is given.

    <div>I kind of know, what to do to get what I want, but I don’t know how to express it in After Effects (or how to combine those expressions that I do know. Basically what I want and what I came up with:</div><div>

    Layer A: nothing, just have those names.

    </div>

    Layer B: nothing, just display text that is entered.

    Layer C: Make an array out of those names in layer A, each value is seperated by a comma, replace those commas with line breaks:

    array = [A.text.sourceText.replace((","),("\r"))]; 

    Which does a line break after every name,
    but I’m pretty sure that it’s not making an array out of it.

    Check every line if it matches with the input in layer B:

    if (B.charAt(0) == A.text.sourceText.charAt(0)) {A.text.sourceText.charAt(0)} 

    Input is “Carl” to make things easier:

    The Expression results in a single C because the first name in the list is Carl, but neither does it show multiple C’s nor does it work with other letters (and even if that would work, I would have to do that for every character seperately to get it to show “Carl” and then all the other names individually as well, wouldn’t I?).

    I know that I’m not using the array (that might not be one in the first place anyway) because I don’t get it combined with “charAt”.

    Finally make those characters that match bold.

    style.setFauxBold(true)

    So how do I combine all these and shorten the expression so that I don’t have to manually do the check line for each first letter, second letter, third letter, etc.?

    Thanks!

  • Filip Vandueren

    March 2, 2021 at 8:54 pm

    I’m assuming that when you type Carl in B,

    C shows:

    Carl Jones (1), Carl Jones (2), Carl Smith…

    but also:

    Carlos Esperanz, Carla Rogers, Geoff Carlston…

    The expression for C’s sourceText:

    names = thisComp.layer("A").text.sourceText.replace("\u200B","").split(","); // this makes it an Array, (after removing any invisible spaces)

    word = thisComp.layer("B").text.sourceText.value;

    regex = new RegExp(word, "gi"); // ,"i" makes it a case insensitive search

    if (word.length > 0) {

    names

    .filter(a => a.match(regex)) // only array elements that match the word

    .map(a => a.trim().replace(regex, "\u200B$&\u200B")) // trim extra whitespace, then surround the found queries with invisible spaces

    .join("\r"); // turns the array into a string

    } else {

    "";

    }

    Now, you can’t set the styling of individual characters, so we have to faux our faux bold with a text animator. That’s why we inserted the invisible spaces (Unicode character 200B = “\u200B”) around every match we want to highlight.

    Paste these keyframes on the layer C, and resulting Animator should be a “faux bold”

    Adobe After Effects 8.0 Keyframe Data
    Units Per Second 30
    Source Width 1
    Source Height 1
    Source Pixel Aspect Ratio 1
    Comp Pixel Aspect Ratio 1
    Text Animators Animator #1 Selectors Expression Selector #1 Amount
    Frame X percent Y percent Z percent
    100 100 100
    Expression Data
    txt=text.sourceText.value.replace(/\r/g,""); // text without line breaks because the textIndex doesn't count them as a character
    sel=false;
    for (i=1; i<textindex; i++)="" {<br=""> if (txt[i-1]=="\u200B") sel = !sel;
    }
    sel && txt[i-1]!="\u200B" ? 100 : 0;
    End of Expression Data
    Text Animators Animator #1 Selectors Expression Selector #1 Based On
    Frame
    1
    Text Animators Animator #1 Properties Stroke Color
    Frame alpha red green blue
    255 255 0 0
    Expression Data
    rgb=text.sourceText.style.fillColor;
    rgb.push(1);
    rgb;
    End of Expression Data
    Text Animators Animator #1 Properties Stroke Width
    Frame
    10
    Expression Data
    text.sourceText.style.fontSize/24;
    End of Expression Data
    Text Animators Animator #1 Properties Tracking Amount
    Frame
    0.8
    Text Animators Animator #1 Properties Tracking Type
    Frame
    3
    Text Animators Animator #1 Properties Stroke Opacity
    Frame percent
    100
    Expression Data
    100
    End of Expression Data
    End of Keyframe Data</textindex;>
  • Philip Peterson

    March 2, 2021 at 11:06 pm

    Oh wow! Looks straight forward when I read it, but I would never have been able to write that myself. Seems like I have been punching way above my weight. I couldn’t find any of this searching for After Effects expressions. I really need to dig deeper into Java for stuff like that I guess? Anyway, thank you so much for your effort Filip!

    2 little things though:

    1. The names in the word array are sorted alphabetically by first name. The expression returns names that partly match the input, like it should, but still uses the alphabetical order it was originally in so that I get matching first names on the bottom and partly matching surnames on top. Example:

    Input: Pet

    Result :

    Adrian Peterson

    Nancy Peters

    Peter Brown

    In some cases even the last three characters of the second surname if they match the input.

    Is there a way to sort those names inside the array so that Peter Brown appears on top, since it matches the input the most up to that point or better yet, determine that it checks the words from left to right instead of “just” checking it?

    2.

    The Animator expression that checks the sourceText returns a syntax error (unexpected token “=”) in line 3.

    for (i=1; i<textindex; i++) ="" //<-this one {<br="">    if (txt[i-1]=="\u200B") sel = !sel;

    I was able to narrow it down to the second “=” after the first brackets but couldn’t find a solution by trial and error.

    Thanks again for your time and effort!

  • Filip Vandueren

    March 3, 2021 at 8:55 am

    Yes, the expression seems to have been mangled by posting it here.

    The for loop should be this:

    for (i=1; i<textindex; i++) {

    if (txt[i-1]=="\u200B") sel = !sel;

    }

    it’s certainly possible to do an extra custom sort() on the array. Let me think about how to phrase that in a function.

  • Filip Vandueren

    March 3, 2021 at 9:06 am

    I think this would do it:

    names = thisComp.layer("A").text.sourceText.replace("\u200B","").split(","); // this makes it an Array, (after removing any invisible spaces)
    word = thisComp.layer("B").text.sourceText.value;
    regex = new RegExp(word, "gi"); // ,"i" makes it a case insensitive search
    if (word.length > 1) {
    names
    .filter(a => a.match(regex)) // only array elements that match the word
    .map(a => a.trim().replace(regex, "\u200B$&\u200B")) // trim extra whitespace, then surround the found queries with invisible spaces
    .sort( (a,b) => a.toLowerCase().indexOf(word.toLowerCase()) - b.toLowerCase().indexOf(word.toLowerCase()))
    .join("\r"); // turns the array into a string
    } else {
    "";
    }

    It sorts by where in the name the substring is found, and for equal positions, should retain the alphabetical sorting that was already in place.

    all the toLowerCase() makes it a bit messy, but that’s to make that part of the code case insensitive too. Could be done with a regular expression too perhaps.

  • Philip Peterson

    March 3, 2021 at 5:32 pm

    Thanks again, Filip!

    Last question, I promise! Is there a way to use .sort on the Animator/ edit the expression in the source text to match those invisible spaces with the input? Right now I’m getting something like this:

    Input: A

    Output: Anita Abrahams

    Anita Abrahams would look a little nicer. I thought about an if statement with .charat() but then I would have to do that for every character. Then I tried switching .sort and .map but that doesn’t do the trick. I also fiddled around inside the Animator’s expression but unfortunately I don’t understand it enough to change it to anything I would want (and also managed to crash AE in the process 😅)

    Thanks!

  • Filip Vandueren

    March 3, 2021 at 6:17 pm

    If you want 1 match per name max, then change the regexp from “gi” to just “i”

  • Philip Peterson

    March 3, 2021 at 6:37 pm

    Well that was a quick fix.

    Thank you so much for your time, effort and patience Filip!

Viewing 1 - 8 of 8 posts

Log in to reply.

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy