Pro un explication, vide illac.

/* 25 december 2019: Bij het technisch bewerken van materiaal van het
   woordenboek Frans-Interlingua van Piet Cleij, toen ik nakeek waar
   de entity " nou precies voor staat (" dus), stuitte ik op
   https://dev.w3.org/html5/html-author/charref, waarin veel meer
   entities staan dan waar ik weet van had. Ze gelden strikt genomen
   voor HTML5, niet voor versie 4, maar doen het waarschijnlijk daarin
   toch ook.

   Onder andere gezien: у voor de Cyrillische У, en de hele rest
   van het Cyrillische alfabet, inclusief Servische variant. En
   Fraktuur-schrift: bijvoorbeeld 𝔄, 𝔄 𝔄. Dat blijkt te
   komen uit een blok voor mathematische symbolen, 1D400-1D7FF
   Mathematical Alphanumeric Symbols,
   http://unicode.org/charts/PDF/U1D400.pdf . Daar zit ook nog een
   andere serie in, vanaf 1D56C, genoemd Bold Fraktur.

   Voor beide hier een converter.

   5 april 2019:
   See also a similar converter, from ASCII to various Unicode
   "pseudo fonts", by António Marques.

   https://groups.google.com/d/msg/sci.lang/0ODlZcCnW68/trjy7cltBAAJ
   https://groups.google.com/d/msg/sci.lang/0ODlZcCnW68/vNzS7lluBAAJ
   https://groups.google.com/d/msg/sci.lang/0ODlZcCnW68/ptI54ZJyBAAJ
   https://groups.google.com/d/msg/sci.lang/0ODlZcCnW68/gHT6eCFzBAAJ
   https://groups.google.com/d/msg/sci.lang/0ODlZcCnW68/bTLID623BAAJ
   https://github.com/entonio/ustyl
   https://groups.google.com/d/msg/sci.lang/0ODlZcCnW68/tC8WdD7RBAAJ
  */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

static int convert (int c, FILE *fpi, FILE *fpo, int bold);
static int baseval_lower = 0x1D586;
static int baseval_upper = 0x1D56C;

int  main (int argc, char **argv)
{
   FILE *fpi = stdin, *fpo = stdout;
   int c;
   int intag = 0, inentity = 0;
   int bold = 0;

   if (argc > 1 && strcmp(argv[1], "-bold") == 0)
   {
      bold = 1;
   }

   while ((c = getc(fpi)) != EOF)
   {
      if (!intag && c == '<')
         intag = 1;
      else if (intag && c == '>')
         intag = 0;
      else if (!inentity && c == '&')
         inentity = 1;
      else if (inentity && c == ';')
         inentity = 0;

      if (intag || inentity)
         putc(c, fpo);
      else
         convert(c, fpi, fpo, bold);
   }

   return 0;
}

static int convert (int c, FILE *fpi, FILE *fpo, int bold)
{
   if (!isascii(c) || !isalpha(c))
   {
      putc(c, fpo);
   }
   else if (bold && islower(c))
   {
      fprintf(fpo, "&#x%05x;", baseval_lower + c - 'a');
   }
   else if (bold && isupper(c))
   {
      fprintf(fpo, "&#x%05x;", baseval_upper + c - 'A');
   }
   else if (strchr("CHIRZ", c))
   {
      int val;

      switch (c)
      {
         case 'C': val = 0x212D; break;
         case 'H': val = 0x210C; break;
         case 'I': val = 0x2111; break;
         case 'R': val = 0x211C; break;
         case 'Z': val = 0x2128; break;
      }
      fprintf(fpo, "&#x%04x;", val);
   }
   else
   {
      fprintf(fpo, "&%cfr;", c);
   }
   return 0;
}