How can I style specific words within a string?

I'm trying to apply styles to specific words within a string. For now I tried creating a paragraph that contains the styles inside (with the idea of appending each word with its style on a string):

var paragraph = "hello <span style=\"color:blue;\">blueeee</span> adios"; txt = createP(paragraph);

For some reason when this is rendered in html, it introduces quotation marks:

<p> "hello " "span style=\"color:blue;\">blueeee</span>" " adios" </p>

Another alternative I though about would be to append word by word (with they specific style), but I'm not sure how to avoid the line break.

Any suggestions? Thanks!

Answers

  • Hi GoToLoop, thanks for your answer. I'm still a bit confused though. From 1. I see title being formatted, but I'm not sure how this gets into a string or paragraph. From 2. I see how you can format strings, but not how you can combine these formatted strings into one (keeping diverse formatting) or combine into a paragraph.

    Basically what I'm looking for is constructing a sentence like "Hello this is my house" where this and house are variables, and have different styles than the rest.

    Thanks!

  • edited August 12

    https://Forum.Processing.org/two/discussion/15473/readme-how-to-format-code-and-text

    It's much easier to help you out if you had a runnable online sample sketch.
    You can host p5.js online here for example: https://OpenProcessing.org/sketch/create

  • I'm using createP here, but not sure is the right way to do it: https://openprocessing.org/sketch/443830

  • edited August 13
    // https://Forum.Processing.org/two/discussion/23783/
    // how-can-i-style-specific-words-within-a-string#Item_5
    
    // GoToLoop (2017-Aug-12)
    
    const WORDS = [ 'Hello', 'Ciao', 'Adios' ],
          COLOR = 'blue';
    
    function setup() {
      noCanvas();
      createP(WORDS[0] + WORDS[1].fontcolor(COLOR) + WORDS[2]);
    }
    
  • This way I'm not able to programatically change the color depending on the word, I believe? Like if (word == 'house') then make it blue, if (word == 'tree') make it green.

    That's why I was trying two ways: 1. Adding parts with the formatting embedded (that's what I was trying to do with the span) 2. Create the whole string and then look for specific words, and style them.

  • edited August 13

    What if you had pairs that could be looked up by the same loop index?:

    const WORDS = [ 'Hello', 'Ciao', 'Adios' ],
          COLOR = ['black', 'blue', 'black];
    

    ...and THEN, instead COLOR being a const, what if you built the second list programmatically based on the values in the first list?

  • How can I have a loop with the createP? If I create multiple createP, these will be adding words in separate lines, right?

    Here's what I'm trying to do, to be clear: from speech-to-text, I'll receive a string, something like:

    "In the morning I've been in the park, I had chicken for lunch and then I went biking with my friends."

    I'll have a JSON file with keywords, like: park, chicken and friends.

    Then, after speech has been transribed to text, I want to highlight those keywords, each with a different color:

    "In the morning I've been in the park, I had chicken for lunch and then I went biking with my friends."

  • edited August 15

    https://OpenProcessing.org/sketch/443843

    index.html:

    <script defer src=http://CDN.JSDelivr.net/npm/p5></script>
    <script defer src=http://CDN.JSDelivr.net/npm/p5/lib/addons/p5.dom.min.js></script>
    <script defer src=sketch.js></script>
    

    sketch.js:

    /**
     * Colorize Each Word (v1.1)
     * GoToLoop (2017-Aug-13)
     *
     * https://Forum.Processing.org/two/discussion/23783/
     * how-can-i-style-specific-words-within-a-string#Item_9
     *
     * https://OpenProcessing.org/sketch/443843
     */
    
    "use strict";
    
    const SENTENCES = [
            'Hello tree ciao. House adios!',
            `In the morning I've been in the park, 
             I had chicken for lunch and then 
             I went biking with my friends.`
          ],
          COLOR_WORDS = {
            house: 'Blue',
            tree: 'LawnGreen',
            park: 'MediumOrchid',
            chicken: 'Peru',
            friends: 'OrangeRed'
          };
    
    function setup() {
      background('white').noCanvas();
    
      for (const msg of SENTENCES)
        createP(colorizeWords(msg, COLOR_WORDS));
    }
    
    function colorizeWords(txt, words) {
      const flags = 'gi', matched = '$&';
    
      for (const w in words) {
        const re = RegExp(w, flags), col = words[w];
        txt = txt.replace(re, matched.fontcolor(col));
      }
    
      return txt;
    }
    
  • edited August 13

    For example:

    1. Receive string
    2. Store each word in word array
    3. Loop through array -- check each word for match in JSON, add color code in parallel wordcolor array
    4. Build contents of createP by looping through word array (and wordcolor array at the same time)
    5. Call createP on contents.
  • edited August 14

    Thanks so much! That worked, and I managed to read the words and colors from a JSON file too. ` function colorizeWords2(txt){ const flags = 'gi', matched = '$&'; // g = global match, don't stop after the first one // i = ignore case

    for (const c in categ){
        for (const e in categ[c].elem){
            console.log(categ[c].elem[e]);
            var w = categ[c].elem[e];
            const re = RegExp(w, flags) // find words that 
            const col = categ[c].color;  
            txt = txt.replace(re, matched.fontcolor(col));
            // replace found keywords (re) with keywords stylized
        }
    }
    return txt;
    

    } `

    One last questions - besides fontcolor, is it possible to either color the background, or the color of the underscore? Like this:

    I couldn't find a method to do that here: https://www.w3schools.com/jsref/jsref_fontcolor.asp

    But there may be another option?

    Thanks so much again!

  • edited August 15

    Besides fontcolor(), is it possible to either color the background or...

    • String::fontcolor() method merely wraps a string up w/ a <font color=""></font> tag.
    • You can hit F12 in any browser and paste 'Processing'.fontcolor('yellow') in its console.
    • You're gonna see that 'Processing' becomes this string now: "<font color="yellow">Processing</font>"
    • Unfortunately, there's no String's shortcut method for background color.
    • However, we can write our own string wrap-up w/ tag <span> + attribute background-color: https://Developer.Mozilla.org/en-US/docs/Web/CSS/background-color
    • Again, you can visit https://OpenProcessing.org/sketch/443843 to see it running online: :bz

    /**
     * Colorize Each Word (v1.2.1)
     * GoToLoop (2017-Aug-13)
     *
     * https://Forum.Processing.org/two/discussion/23783/
     * how-can-i-style-specific-words-within-a-string#Item_12
     *
     * https://OpenProcessing.org/sketch/443843
     */
    
    "use strict";
    
    const SENTENCES = [
            'Hello tree ciao. House adios!',
            `In the morning I've been in the park,
             I had chicken for lunch and then
             I went biking with my friends.`
          ],
          COLOR_WORDS = {
            house: 'Blue',
            tree: 'LawnGreen',
            park: 'MediumOrchid',
            chicken: 'Peru',
            friends: 'OrangeRed'
          };
    
    function setup() {
      background('white').noCanvas();
    
      for (const msg of SENTENCES)
        //createP(colorizeWords(msg, COLOR_WORDS));
        createP(colorizeBGWords(msg, COLOR_WORDS));
    }
    
    function colorizeWords(txt, words) {
      const flags = 'gi', matched = '$&';
    
      for (const w in words) {
        const re = RegExp(w, flags), col = words[w];
        txt = txt.replace(re, matched.fontcolor(col));
      }
    
      return txt;
    }
    
    function colorizeBGWords(txt, words) {
      const flags = 'gi', matched = '$&',
            span = '<span style=background-color:',
            close = '>' + matched + '</span>';
    
      for (const w in words) {
        const re = RegExp(w, flags), col = words[w];
        txt = txt.replace(re, span + col + close);
      }
    
      return txt;
    }
    
  • edited August 16
    • I've refactored the sketch as version 2.x.x for performance reasons.
    • It gets rid of the for...in loop within colorizeWords().
    • It also uses only 1 generic RegExp /[-\w\xC0-\u02AF]+/g.
    • Rather than instantiating new 1s for each word of the passed object list.
    • That customized RegExp matches accented Latin characters too.
    • For other character ranges go here: http://Kourge.net/projects/regexp-unicode-block
    • And instead of passing a substitute string for replace(), it passes a callback.
    • That callback function checks whether the current matched word has a corresponding colour.
    • If true, it returns the matched word wrapped up w/ a styling tag for the found colour.
    • Otherwise, it returns the matched word unaltered.
    • BtW, new version is now hosted here: http://Bl.ocks.org/GoSubRoutine/de13a236ab6cc666320d39a1b04a2315

    index.html:

    <!DOCTYPE html>
    <meta charset=utf-8>
    <script defer src=http://CDN.JSDelivr.net/npm/p5></script>
    <script defer src=http://CDN.JSDelivr.net/npm/p5/lib/addons/p5.dom.min.js></script>
    <script defer src=sketch.js></script>
    

    sketch.js:

    /**
     * Colorize Each Word (v2.0.3)
     * GoToLoop (2017-Aug-13)
     *
     * https://Forum.Processing.org/two/discussion/23783/
     * how-can-i-style-specific-words-within-a-string#Item_13
     *
     * http://Bl.ocks.org/GoSubRoutine/de13a236ab6cc666320d39a1b04a2315
     * https://OpenProcessing.org/sketch/443843
     */
    
    "use strict";
    
    const SENTENCES = [
            'Hello tree ciao. House adios!',
            `In the morning I've been in the park,
             I had chicken for lunch and then
             I went biking with my friends.`
          ],
          COLOR_WORDS = {
            house: 'Blue',
            tree: 'LawnGreen',
            park: 'MediumOrchid',
            chicken: 'Peru',
            friends: 'OrangeRed'
          };
    
    function setup() {
      noCanvas();
      for (const msg of SENTENCES)
        createP(colorizeWords(msg, COLOR_WORDS, true));
    }
    
    function colorizeWords(txt, words, isBG) {
      const re = /[-'\w\xC0-\u02AF]+/g,
            cb = isBG && createBGMatch(words) || createFGMatch(words);
      return txt.replace(re, cb);
    }
    
    function createFGMatch(colorWords) {
      return matched => {
        const colour = colorWords[matched.toLowerCase()];
        return colour && matched.fontcolor(colour) || matched;
      };
    }
    
    function createBGMatch(colorWords) {
      return matched => {
        const colour = colorWords[matched.toLowerCase()];
        if (!colour)  return matched;
    
        const spanOpen = '<span style=background-color:',
              spanClose = '>' + matched + '</span>';
        return spanOpen + colour + spanClose;
      };
    }
    
  • edited August 16
    • Version 3.x.x is the same as 2.x.x.
    • However, functions colorizeWords(), createFGMatch() & createBGMatch() are now encapsulated inside class Colorize as static methods.
    • And all string & RegExp constants are now static properties within Colorize.
    • Therefore, in order to invoke colorizeWords(), we now need to prefix it w/ Colorize: Colorize.colorizeWords(msg, COLOR_WORDS, true)
    • Sketch is still hosted online here: http://Bl.ocks.org/GoSubRoutine/de13a236ab6cc666320d39a1b04a2315
    /**
     * Colorize Each Word (v3.0)
     * GoToLoop (2017-Aug-13)
     *
     * https://Forum.Processing.org/two/discussion/23783/
     * how-can-i-style-specific-words-within-a-string#Item_14
     *
     * http://Bl.ocks.org/GoSubRoutine/de13a236ab6cc666320d39a1b04a2315
     * https://OpenProcessing.org/sketch/443843
     */
    
    "use strict";
    
    const SENTENCES = [
            'Hello tree ciao. House adios!',
            `In the morning I've been in the park,
             I had chicken for lunch and then
             I went biking with my friends.`
          ],
          COLOR_WORDS = {
            house: 'Blue',
            tree: 'LawnGreen',
            park: 'MediumOrchid',
            chicken: 'Peru',
            friends: 'OrangeRed'
          };
    
    function setup() {
      noCanvas();
      for (const msg of SENTENCES)
        //createP(Colorize.colorizeWords(msg, COLOR_WORDS));
        createP(Colorize.colorizeWords(msg, COLOR_WORDS, true));
    }
    
    class Colorize {
      static get RE() {
        delete this.RE;
        //return this.RE = /[-'\w\xC0-\u02AF]+/g;
        return this.RE = /\w{3,}/g;
      }
    
      static get SPAN_OPEN() {
        delete this.SPAN_OPEN;
        return this.SPAN_OPEN = '<span style=background-color:';
      }
    
      static get SPAN_CLOSE() {
        delete this.SPAN_CLOSE;
        return this.SPAN_CLOSE = '</span>';
      }
    
      static get GT() {
        delete this.GT;
        return this.GT = '>';
      }
    
      static colorizeWords(txt, words, isBG) {
        if (words)  this.colorWords = words;
        return txt.replace(this.RE, isBG && this.MatchBG || this.MatchFG);
      }
    
      static MatchFG(matched) {
        const colour = Colorize.colorWords[matched.toLowerCase()];
        return colour && matched.fontcolor(colour) || matched;
      }
    
      static MatchBG(matched) {
        const C = Colorize, colour = C.colorWords[matched.toLowerCase()];
        return !colour && matched ||
               C.SPAN_OPEN + colour + C.GT + matched + C.SPAN_CLOSE;
      }
    }
    
Sign In or Register to comment.