skip to Main Content

I have this code that converts plain text to Unicode styled characters:

function convertText(text, style) {

  // 1. Convert the text to the bold type with the unicode.
  const conv = {
    c: function(text, obj) {return text.replace(new RegExp(`[${obj.reduce((s, {r}) => s += r, "")}]`, "g"), e => {
      const t = e.codePointAt(0);
      if ((t >= 48 && t <= 57) || (t >= 65 && t <= 90) || (t >= 97 && t <= 122)) {
        return obj.reduce((s, {r, d}) => {
          if (new RegExp(`[${r}]`).test(e)) s = String.fromCodePoint(e.codePointAt(0) + d);
          return s;
        }, "")
      }
      return e;
    })},
    bold: function(text) {return this.c(text, [{r: "0-9", d: 120734}, {r: "A-Z", d: 120211}, {r: "a-z", d: 120205}])},
    italic: function(text) {return this.c(text, [{r: "A-Z", d: 120263}, {r: "a-z", d: 120257}])},
    boldItalic: function(text) {return this.c(text, [{r: "A-Z", d: 120315}, {r: "a-z", d: 120309}])},
  };

  if(style == 'bold')
    return(conv.bold(text));
  else if(style == 'italic')
    return(conv.italic(text));
  else if(style == 'bolditalic')
    return(conv.boldItalic(text));
  else
    return text;
}

which I have found on this StackOverflow link:
Google script string with style

I tried reversing the code to convert the styled unicode characters to plain text but failed. Hopefully somebody could reverse the code to get the plain text from the styled unicode characters.

2

Answers


  1. Although I’m not sure whether I could correctly understand your expected result, how about the following sample script?

    Sample script:

    In this sample, normalize() is used.

    function convertText(text, style) {
    
      // 1. Convert the text to the bold type with the unicode.
      const conv = {
        c: function (text, obj) {
          return text.replace(new RegExp(`[${obj.reduce((s, { r }) => s += r, "")}]`, "g"), e => {
            const t = e.codePointAt(0);
            if ((t >= 48 && t <= 57) || (t >= 65 && t <= 90) || (t >= 97 && t <= 122)) {
              return obj.reduce((s, { r, d }) => {
                if (new RegExp(`[${r}]`).test(e)) s = String.fromCodePoint(e.codePointAt(0) + d);
                return s;
              }, "")
            }
            return e;
          })
        },
        bold: function (text) { return this.c(text, [{ r: "0-9", d: 120734 }, { r: "A-Z", d: 120211 }, { r: "a-z", d: 120205 }]) },
        italic: function (text) { return this.c(text, [{ r: "A-Z", d: 120263 }, { r: "a-z", d: 120257 }]) },
        boldItalic: function (text) { return this.c(text, [{ r: "A-Z", d: 120315 }, { r: "a-z", d: 120309 }]) },
      };
    
      if (style == 'bold')
        return (conv.bold(text));
      else if (style == 'italic')
        return (conv.italic(text));
      else if (style == 'bolditalic')
        return (conv.boldItalic(text));
      else
        return text;
    }
    
    // Please run this function.
    function sample() {
      const srcText = "Sample Text";
    
      const t1 = convertText(srcText, "italic");
      const t2 = convertText(srcText, "bold");
      const t3 = convertText(srcText, "bolditalic");
    
      const text1 = Array(3).fill(srcText).join("");
      const text2 = t1 + t2 + t3;
      const text3 = text2.normalize("NFKC");
    
      console.log({ text1, text2, text3 });
    }
    

    When this script is run, the following result is obtained. In this case, I thought that NFKC and NFKD might be able to be used.

    {
      "text1":"Sample TextSample TextSample Text",
      "text2":"𝘚𝘢𝘮𝘱𝘭𝘦 𝘛𝘦𝘹𝘵𝗦𝗮𝗺𝗽𝗹𝗲 𝗧𝗲𝘅𝘁𝙎𝙖𝙢𝙥𝙡𝙚 𝙏𝙚𝙭𝙩",
      "text3":"Sample TextSample TextSample Text"
    }
    

    In this sample output, the original text is converted to italic, bold, and bolditalic and the converted text is also converted to normal text. text1, text2, and text1 are the source text, and the converted text, and the normal text converted from the converted text, respectively.

    Testing:

    function convertText(text, style) {
    
      // 1. Convert the text to the bold type with the unicode.
      const conv = {
        c: function (text, obj) {
          return text.replace(new RegExp(`[${obj.reduce((s, { r }) => s += r, "")}]`, "g"), e => {
            const t = e.codePointAt(0);
            if ((t >= 48 && t <= 57) || (t >= 65 && t <= 90) || (t >= 97 && t <= 122)) {
              return obj.reduce((s, { r, d }) => {
                if (new RegExp(`[${r}]`).test(e)) s = String.fromCodePoint(e.codePointAt(0) + d);
                return s;
              }, "")
            }
            return e;
          })
        },
        bold: function (text) { return this.c(text, [{ r: "0-9", d: 120734 }, { r: "A-Z", d: 120211 }, { r: "a-z", d: 120205 }]) },
        italic: function (text) { return this.c(text, [{ r: "A-Z", d: 120263 }, { r: "a-z", d: 120257 }]) },
        boldItalic: function (text) { return this.c(text, [{ r: "A-Z", d: 120315 }, { r: "a-z", d: 120309 }]) },
      };
    
      if (style == 'bold')
        return (conv.bold(text));
      else if (style == 'italic')
        return (conv.italic(text));
      else if (style == 'bolditalic')
        return (conv.boldItalic(text));
      else
        return text;
    }
    
    // Please run this function.
    function sample() {
      const srcText = "Sample Text";
    
      const t1 = convertText(srcText, "italic");
      const t2 = convertText(srcText, "bold");
      const t3 = convertText(srcText, "bolditalic");
    
      const text1 = Array(3).fill(srcText).join("");
      const text2 = t1 + t2 + t3;
      const text3 = text2.normalize("NFKC");
    
      console.log({ text1, text2, text3 });
    }
    
    sample();

    Reference:

    Login or Signup to reply.
  2. Building on Tanaike’s work, here’s a function that will accept any text and return it formatted or plain, as requested.

    /**
    * Converts text to bold, italic or plain Unicode characters, as in
    * '𝗦𝗮𝗺𝗽𝗹𝗲 𝘁𝗲𝘅𝘁', '𝘚𝘢𝘮𝘱𝘭𝘦 𝘵𝘦𝘹𝘵', '𝙎𝙖𝙢𝙥𝙡𝙚 𝙩𝙚𝙭𝙩', 'Sample text'.
    * Numbers can be bolded but not italicized.
    *
    * @param {"A2:D42"} text Text strings to format.
    * @param {"bold italic"} style One of "bold", "italic", "bold italic" or "plain".
    * @return {String[][]} The formatted text.
    * @customfunction
    */
    function unicodeFormat(text, style) {
      // see https://stackoverflow.com/a/79113754/13045193
      const conv = {
        c: (text, spec) =>
          text.replace(new RegExp(`[${spec.reduce((s, { r }) => s += r, '')}]`, 'g'), e => {
            const t = e.codePointAt(0);
            if (!((48 <= t && t <= 57) || (65 <= t && t <= 90) || (97 <= t && t <= 122))) return e;
            return spec.reduce((s, { r, d }) => e.match(new RegExp(`[${r}]`)) ? String.fromCodePoint(e.codePointAt(0) + d) : s, '');
          }),
        plain: function (text) { return text.normalize('NFKC') },
        bold: function (text) { return this.c(text, [{ r: '0-9', d: 120734 }, { r: 'A-Z', d: 120211 }, { r: 'a-z', d: 120205 }]) },
        italic: function (text) { return this.c(text, [{ r: 'A-Z', d: 120263 }, { r: 'a-z', d: 120257 }]) },
        bolditalic: function (text) { return this.c(text, [{ r: '0-9', d: 120734 }, { r: 'A-Z', d: 120315 }, { r: 'a-z', d: 120309 }]) },
      };
      const s = String(style).toLowerCase().split(' ').sort().join('').replace(/[^a-z]/g, '');
      if (!conv[s]) throw new Error(`uniCodeFormat expected a style of "bold", "italic", "bold italic" or "plain", but got "${style}" instead.`);
      const _format = (text) =>
        Array.isArray(text)
          ? text.map(_format)
          : text || text === 0 ? conv[s](conv.plain(String(text))) : null;
      return _format(text);
    }
    

    Supports arrays of text. Can re-format already formatted text. The function can be called from another JavaScript function, or directly from a spreadsheet formula as a custom function.

    Here’s a short test function that converts text to various formats, then converts those formatted strings back to plain text:

    function test() {
      const formattedArray = ['bold', 'italic', 'bold italic', 'plain']
        .map(format => unicodeFormat('Sample text 1234567890', format));
      const plainArray = unicodeFormat(formattedArray, 'plain');
      console.log(formattedArray);
      console.log(plainArray);
    }
    

    To test this as a custom function, enter text in column A and put this formula in row 1 of a free column:

    =unicodeFormat(A1:A, "bold italic")
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search