小道具：文字コードの変換と確認など

バラバラに作った小道具

- 正規化表現
- コード ポイント の表示
- innerHTML 代入テスト
- 英数字の変換
- 円内文字への変換
- 丸括弧付き文字への変換

を1つにまとめてみた。

<p class="codepen" data-height="460" data-default-tab="result" data-slug-hash="zYJmMXM" data-user="ikiuo" style="height: 460px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ikiuo/pen/zYJmMXM">
  文字変換と確認</a> by Ikiuo (<a href="https://codepen.io/ikiuo">@ikiuo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<details><summary>ソースコード (HTML+JavaScript)</summary><div>

```html:
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>各種処理</title>
    <style>
      table {
          border: solid 1px #ccc;
          border-collaspe: collaspe;
          border-spacing: 0;
      }
      th, td {
          border: solid 1px #ccc;
      }
      th {
          background: #eee;
      }
      td {
          padding: 0px;
          margin: 0px;
      }

      .left {
          text-align: left;
      }
    </style>
  </head>
  <body>

    <table>
      <tr>
        <th>入<br>力</th>
        <td>
          <textarea cols="80" rows="8" oninput="onInput(this.value)"></textarea>
        </td>
      </tr>
      <tr>
        <th>形<br/>式</th>
        <td>
          &nbsp;
          <button onclick="onClick('Normalize')">正規化表現</button>
          <button onclick="onClick('CodePoint')">コード ポイント</button>
          <button onclick="onClick('InnerHTML')">innerHTML</button>
          <br/>&nbsp;
          <button onclick="onClick('AlphaNumeric')">英数字の変換</button>
          <button onclick="onClick('Circled')">円内文字への変換</button>
          <button onclick="onClick('Parenthesized')">丸括弧付き文字への変換</button>
        </td>
      </tr>
    </table>

    <p>出力：項目ボタンのクリックで、クリップボードへ結果(テキスト)をコピーします。</p>

    <table id="Normalize">
      <tr><th colspan="2">正規化表現</th></tr>
      <tr><th>種類</th><th>結果</th></tr>
    </table>
    <table id="CodePoint">
      <tr><th colspan="2">コード ポイント</th></tr>
      <tr><th>種類</th><th>結果</th></tr>
    </table>
    <table id="InnerHTML">
      <tr><th colspan="2">InnerHTML</th></tr>
      <tr><td id="InnerHTML_output"></td></tr>
    </table>

    <table id="AlphaNumeric">
      <tr><th colspan="2">英数字の変換</th></tr>
      <tr><th>種類</th><th>結果</th></tr>
    </table>
    <table id="Circled">
      <tr><th colspan="2">円内文字への変換</th></tr>
      <tr><th>種類</th><th>結果</th></tr>
    </table>
    <table id="Parenthesized">
      <tr><th colspan="2">丸括弧付き文字への変換</th></tr>
      <tr><th>種類</th><th>結果</th></tr>
      <tr>
        <th class="left">
          <button onclick="toClipboard(Parenthesized_output.innerText)">
            Parenthesized
          </button>
        </th>
        <td id="Parenthesized_output"></td>
      </tr>
    </table>

    <script>

      // ----------------------------------------------------------------------

      const OutputTable = [
          'Normalize', 'CodePoint', 'InnerHTML',
          'AlphaNumeric', 'Circled', 'Parenthesized',
      ];

      var lastMode = '';
      var lastText = '';

      // ----------------------------------------------------------------------

      function toUTF8(ucs4) {
          return ((ucs4 < 0x00080) ? [ucs4] :
                  (ucs4 < 0x00800) ? [0xc0 | ((ucs4 >> 6) & 0x1f),
                                      0x80 | ((ucs4 >> 0) & 0x3f)] :
                  (ucs4 < 0x10000) ? [0xe0 | ((ucs4 >> 12) & 0x0f),
                                      0x80 | ((ucs4 >>  6) & 0x3f),
                                      0x80 | ((ucs4 >>  0) & 0x3f)] :
                  [0xf0 | ((ucs4 >> 18) & 0x07),
                   0x80 | ((ucs4 >> 12) & 0x3f),
                   0x80 | ((ucs4 >>  6) & 0x3f),
                   0x80 | ((ucs4 >>  0) & 0x3f)]);
      }

      const toDec = (code => code.toString(10));
      const toHex = ((code, prefix) => (prefix ? '0x' : '') + (
          `00000000${code.toString(16).toUpperCase()}`
              .substr(-(((8 + 31 - Math.clz32(code)) >> 3) << 1))));
      const toString = ((code, base, prefix) =>
          ((base == 16) ? toHex(code, prefix) : toDec(code)));

      function encodeHTML(inp) {
          const m = { '<':'&lt;', '&':'&amp;', '>':'&gt;', '\n':'<br/>' };
          return [...inp].map((c) => m[c] ?? c).join('');
      }

      function encodeHTMLN(inp) {
          const m = {
              '<':'&lt;', '&':'&amp;', '>':'&gt;',
              '\n':'<span style="color: red"><small>\\n</small></span>'
          };
          return [...inp].map((c) => m[c] ?? c).join('');
      }

      // ----------------------------------------------------------------------

      class CodePointRuby {
          static TypeTable = ['UTF-32', 'UTF-16', 'UTF-8'];

          static flagSet = new Set([...Array(0x1f200 - 0x1f1e6)].map((_, n) => n + 0x1f1e6));
          static varselSet = new Set([
              [...Array(0x10)].map((_, n) => n + 0x0ff00),
              [...Array(0xf0)].map((_, n) => n + 0xe0100),
          ].flat());

          constructor(text) {
              const C = CodePointRuby;
              this.C = C;

              const lines = [];
              {
                  let line = '';
                  for (const c of text) {
                      line = line + c;
                      if (c == '\n') {
                          lines.push(line);
                          line = '';
                      }
                  }
                  if (line.length)
                      lines.push(line);
              }

              this.lines = [];
              for (const line of lines) {
                  const chars = [];
                  let lastChar = '';
                  [...line].forEach(c => {
                      const lc = lastChar;
                      lastChar = c;
                      if (C.varselSet.has(c)) {
                          if (chars.length) {
                              chars[chars.length - 1] += c;
                              return;
                          }
                      } else if (C.flagSet.has(c)) {
                          if (C.flagSet.has(lastChar)) {
                              chars[chars.length - 1] += c;
                              lastChar = '';
                              return;
                          }
                      }
                      chars.push(c);
                  });
                  this.lines.push(chars);
              }
          }

          toHTML(mode) {
              const C = this.C;

              const bUTF8  = (mode == 'UTF-8');
              const bUTF16 = (mode == 'UTF-16');
              const bUTF32 = (mode == 'UTF-32');
              const nBase = 16;
              const bPrefix = false;

              let out = '';
              for (const line of this.lines) {
                  out += '<p>';
                  for (const data of line) {
                      let codes;
                      let ruby = `<ruby>${encodeHTMLN(data)}<rp>(</rp>`;
                      if (bUTF32)
                          codes = [...data].map(c => c.codePointAt(0));
                      else if (bUTF16) {
                          codes = [];
                          for (const n in data)
                              codes.push(data.charCodeAt(n));
                      } else if (bUTF8)
                          codes = [...data].map(c => toUTF8(c.codePointAt(0))).flat();
                      ruby += `<rt>[${codes.map(c => toString(c, nBase, bPrefix)).join(',')}]</rt>`;
                      ruby += '<rp>)</rp></ruby>';
                      out += ruby;
                  }
                  out += '</p>';
              }
              return out;
          }

          static toId(name) {
              return `CodePoint_${name.replaceAll('-', '_')}`;
          }
      }

      // ----------------------------------------------------------------------

      class NormalizeDiff {
          static TypeTable = ['NFC', 'NFD', 'NFKC', 'NFKD'];

          constructor(mode, text) {
              this.mode = mode;
              this.characters = [...text].map(c => {
                  const n  = c.normalize(mode);
                  return { chk:(c == n), inp:c, out:n }
              });

              let pos = 0;
              let end = this.characters.length;
              while (pos < end)
                  pos += this.checkComposite(pos, end);

              this.characters.forEach(c => c.out = encodeHTML(c.out));
          }

          checkComposite(start, end) {
              const mode = this.mode;
              const inp = this.characters;

              let pos = start;
              if (!inp[pos].chk)
                  return 1;

              let s = inp[pos].inp;
              let t = s;
              while (++pos < end) {
                  const c = inp[pos];
                  if (!c.chk)
                      break;
                  s += c.inp;
                  t = s.normalize(mode);
                  if (s == t)
                      continue;
                  const sc = [...s];
                  if (sc.length == 1)
                      continue;
                  const tc = [...t];
                  if (sc.pop() != tc.pop())
                      continue;
                  s = sc.join('');
                  t = tc.join('');
                  break;
              }

              const len = pos - start;
              {
                  const sc = [...s];
                  const tc = [...t];
                  let scnt;
                  for (scnt = 0; scnt < sc.length; scnt++)
                      if (sc[scnt] != tc[scnt])
                          break;
                  start += scnt;
              }
              if (start < pos) {
                  s = '';
                  for (let p = start; p < pos; p++)
                      s += inp[p].inp;
                  t = s.normalize(mode);

                  inp[start].chk = false;
                  inp[start].out = t;
                  while (++start < pos) {
                      inp[start].chk = false;
                      inp[start].out = '';
                  }
              }
              return len;
          }

          toHTML() {
              return this.characters.map(
                  (c) => c.chk ? c.out : !c.out.length ? '' :
                      `<span style="background-color: #fbb">${c.out}</span>`
              ).join('');
          }

          static toId(name) {
              return `Normalize_${name}`;
          }
      }

      // ----------------------------------------------------------------------

      class ConvertAlphaNumeric {
          static TypeTable = {
              'FULLWIDTH': ['０','１','２','３','４','５','６','７','８','９','Ａ','Ｂ','Ｃ','Ｄ','Ｅ','Ｆ','Ｇ','Ｈ','Ｉ','Ｊ','Ｋ','Ｌ','Ｍ','Ｎ','Ｏ','Ｐ','Ｑ','Ｒ','Ｓ','Ｔ','Ｕ','Ｖ','Ｗ','Ｘ','Ｙ','Ｚ','ａ','ｂ','ｃ','ｄ','ｅ','ｆ','ｇ','ｈ','ｉ','ｊ','ｋ','ｌ','ｍ','ｎ','ｏ','ｐ','ｑ','ｒ','ｓ','ｔ','ｕ','ｖ','ｗ','ｘ','ｙ','ｚ'],
              'MATHEMATICAL BOLD': ['𝟎','𝟏','𝟐','𝟑','𝟒','𝟓','𝟔','𝟕','𝟖','𝟗','𝐀','𝐁','𝐂','𝐃','𝐄','𝐅','𝐆','𝐇','𝐈','𝐉','𝐊','𝐋','𝐌','𝐍','𝐎','𝐏','𝐐','𝐑','𝐒','𝐓','𝐔','𝐕','𝐖','𝐗','𝐘','𝐙','𝐚','𝐛','𝐜','𝐝','𝐞','𝐟','𝐠','𝐡','𝐢','𝐣','𝐤','𝐥','𝐦','𝐧','𝐨','𝐩','𝐪','𝐫','𝐬','𝐭','𝐮','𝐯','𝐰','𝐱','𝐲','𝐳'],
              'MATHEMATICAL ITALIC': ['','','','','','','','','','','𝐴','𝐵','𝐶','𝐷','𝐸','𝐹','𝐺','𝐻','𝐼','𝐽','𝐾','𝐿','𝑀','𝑁','𝑂','𝑃','𝑄','𝑅','𝑆','𝑇','𝑈','𝑉','𝑊','𝑋','𝑌','𝑍','𝑎','𝑏','𝑐','𝑑','𝑒','𝑓','𝑔','ℎ','𝑖','𝑗','𝑘','𝑙','𝑚','𝑛','𝑜','𝑝','𝑞','𝑟','𝑠','𝑡','𝑢','𝑣','𝑤','𝑥','𝑦','𝑧'],
              'MATHEMATICAL BOLD ITALIC': ['','','','','','','','','','','𝑨','𝑩','𝑪','𝑫','𝑬','𝑭','𝑮','𝑯','𝑰','𝑱','𝑲','𝑳','𝑴','𝑵','𝑶','𝑷','𝑸','𝑹','𝑺','𝑻','𝑼','𝑽','𝑾','𝑿','𝒀','𝒁','𝒂','𝒃','𝒄','𝒅','𝒆','𝒇','𝒈','𝒉','𝒊','𝒋','𝒌','𝒍','𝒎','𝒏','𝒐','𝒑','𝒒','𝒓','𝒔','𝒕','𝒖','𝒗','𝒘','𝒙','𝒚','𝒛'],
              'MATHEMATICAL SCRIPT': ['','','','','','','','','','','𝒜','ℬ','𝒞','𝒟','ℰ','ℱ','𝒢','ℋ','ℐ','𝒥','𝒦','ℒ','ℳ','𝒩','𝒪','𝒫','𝒬','ℛ','𝒮','𝒯','𝒰','𝒱','𝒲','𝒳','𝒴','𝒵','𝒶','𝒷','𝒸','𝒹','ℯ','𝒻','ℊ','𝒽','𝒾','𝒿','𝓀','𝓁','𝓂','𝓃','ℴ','𝓅','𝓆','𝓇','𝓈','𝓉','𝓊','𝓋','𝓌','𝓍','𝓎','𝓏'],
              'MATHEMATICAL SCRIPT (CHANCERY)': ['','','','','','','','','','','𝒜︀','𝒝︀','𝒞︀','𝒟︀','𝒠︀','𝒡︀','𝒢︀','𝒣︀','𝒤︀','𝒥︀','𝒦︀','𝒧︀','𝒨︀','𝒩︀','𝒪︀','𝒫︀','𝒬︀','𝒭︀','𝒮︀','𝒯︀','𝒰︀','𝒱︀','𝒲︀','𝒳︀','𝒴︀','𝒵︀','𝒶','𝒷','𝒸','𝒹','ℯ','𝒻','ℊ','𝒽','𝒾','𝒿','𝓀','𝓁','𝓂','𝓃','ℴ','𝓅','𝓆','𝓇','𝓈','𝓉','𝓊','𝓋','𝓌','𝓍','𝓎','𝓏'],
              'MATHEMATICAL SCRIPT (ROUNDHAND)': ['','','','','','','','','','','𝒜︁','𝒝︁','𝒞︁','𝒟︁','𝒠︁','𝒡︁','𝒢︁','𝒣︁','𝒤︁','𝒥︁','𝒦︁','𝒧︁','𝒨︁','𝒩︁','𝒪︁','𝒫︁','𝒬︁','𝒭︁','𝒮︁','𝒯︁','𝒰︁','𝒱︁','𝒲︁','𝒳︁','𝒴︁','𝒵︁','𝒶','𝒷','𝒸','𝒹','ℯ','𝒻','ℊ','𝒽','𝒾','𝒿','𝓀','𝓁','𝓂','𝓃','ℴ','𝓅','𝓆','𝓇','𝓈','𝓉','𝓊','𝓋','𝓌','𝓍','𝓎','𝓏'],
              'MATHEMATICAL BOLD SCRIPT': ['','','','','','','','','','','𝓐','𝓑','𝓒','𝓓','𝓔','𝓕','𝓖','𝓗','𝓘','𝓙','𝓚','𝓛','𝓜','𝓝','𝓞','𝓟','𝓠','𝓡','𝓢','𝓣','𝓤','𝓥','𝓦','𝓧','𝓨','𝓩','𝓪','𝓫','𝓬','𝓭','𝓮','𝓯','𝓰','𝓱','𝓲','𝓳','𝓴','𝓵','𝓶','𝓷','𝓸','𝓹','𝓺','𝓻','𝓼','𝓽','𝓾','𝓿','𝔀','𝔁','𝔂','𝔃'],
              'MATHEMATICAL FRAKTUR': ['','','','','','','','','','','𝔄','𝔅','ℭ','𝔇','𝔈','𝔉','𝔊','ℌ','ℑ','𝔍','𝔎','𝔏','𝔐','𝔑','𝔒','𝔓','𝔔','ℜ','𝔖','𝔗','𝔘','𝔙','𝔚','𝔛','𝔜','ℨ','𝔞','𝔟','𝔠','𝔡','𝔢','𝔣','𝔤','𝔥','𝔦','𝔧','𝔨','𝔩','𝔪','𝔫','𝔬','𝔭','𝔮','𝔯','𝔰','𝔱','𝔲','𝔳','𝔴','𝔵','𝔶','𝔷'],
              'MATHEMATICAL BOLD FRAKTUR': ['','','','','','','','','','','𝕬','𝕭','𝕮','𝕯','𝕰','𝕱','𝕲','𝕳','𝕴','𝕵','𝕶','𝕷','𝕸','𝕹','𝕺','𝕻','𝕼','𝕽','𝕾','𝕿','𝖀','𝖁','𝖂','𝖃','𝖄','𝖅','𝖆','𝖇','𝖈','𝖉','𝖊','𝖋','𝖌','𝖍','𝖎','𝖏','𝖐','𝖑','𝖒','𝖓','𝖔','𝖕','𝖖','𝖗','𝖘','𝖙','𝖚','𝖛','𝖜','𝖝','𝖞','𝖟'],
              'MATHEMATICAL DOUBLE STRUCK': ['𝟘','𝟙','𝟚','𝟛','𝟜','𝟝','𝟞','𝟟','𝟠','𝟡','𝔸','𝔹','ℂ','𝔻','𝔼','𝔽','𝔾','ℍ','𝕀','𝕁','𝕂','𝕃','𝕄','ℕ','𝕆','ℙ','ℚ','ℝ','𝕊','𝕋','𝕌','𝕍','𝕎','𝕏','𝕐','ℤ','𝕒','𝕓','𝕔','𝕕','𝕖','𝕗','𝕘','𝕙','𝕚','𝕛','𝕜','𝕝','𝕞','𝕟','𝕠','𝕡','𝕢','𝕣','𝕤','𝕥','𝕦','𝕧','𝕨','𝕩','𝕪','𝕫'],
              'MATHEMATICAL SANS SERIF': ['𝟢','𝟣','𝟤','𝟥','𝟦','𝟧','𝟨','𝟩','𝟪','𝟫','𝖠','𝖡','𝖢','𝖣','𝖤','𝖥','𝖦','𝖧','𝖨','𝖩','𝖪','𝖫','𝖬','𝖭','𝖮','𝖯','𝖰','𝖱','𝖲','𝖳','𝖴','𝖵','𝖶','𝖷','𝖸','𝖹','𝖺','𝖻','𝖼','𝖽','𝖾','𝖿','𝗀','𝗁','𝗂','𝗃','𝗄','𝗅','𝗆','𝗇','𝗈','𝗉','𝗊','𝗋','𝗌','𝗍','𝗎','𝗏','𝗐','𝗑','𝗒','𝗓'],
              'MATHEMATICAL SANS SERIF BOLD': ['𝟬','𝟭','𝟮','𝟯','𝟰','𝟱','𝟲','𝟳','𝟴','𝟵','𝗔','𝗕','𝗖','𝗗','𝗘','𝗙','𝗚','𝗛','𝗜','𝗝','𝗞','𝗟','𝗠','𝗡','𝗢','𝗣','𝗤','𝗥','𝗦','𝗧','𝗨','𝗩','𝗪','𝗫','𝗬','𝗭','𝗮','𝗯','𝗰','𝗱','𝗲','𝗳','𝗴','𝗵','𝗶','𝗷','𝗸','𝗹','𝗺','𝗻','𝗼','𝗽','𝗾','𝗿','𝘀','𝘁','𝘂','𝘃','𝘄','𝘅','𝘆','𝘇'],
              'MATHEMATICAL SANS SERIF ITALIC': ['','','','','','','','','','','𝘈','𝘉','𝘊','𝘋','𝘌','𝘍','𝘎','𝘏','𝘐','𝘑','𝘒','𝘓','𝘔','𝘕','𝘖','𝘗','𝘘','𝘙','𝘚','𝘛','𝘜','𝘝','𝘞','𝘟','𝘠','𝘡','𝘢','𝘣','𝘤','𝘥','𝘦','𝘧','𝘨','𝘩','𝘪','𝘫','𝘬','𝘭','𝘮','𝘯','𝘰','𝘱','𝘲','𝘳','𝘴','𝘵','𝘶','𝘷','𝘸','𝘹','𝘺','𝘻'],
              'MATHEMATICAL SANS SERIF BOLD ITALIC': ['','','','','','','','','','','𝘼','𝘽','𝘾','𝘿','𝙀','𝙁','𝙂','𝙃','𝙄','𝙅','𝙆','𝙇','𝙈','𝙉','𝙊','𝙋','𝙌','𝙍','𝙎','𝙏','𝙐','𝙑','𝙒','𝙓','𝙔','𝙕','𝙖','𝙗','𝙘','𝙙','𝙚','𝙛','𝙜','𝙝','𝙞','𝙟','𝙠','𝙡','𝙢','𝙣','𝙤','𝙥','𝙦','𝙧','𝙨','𝙩','𝙪','𝙫','𝙬','𝙭','𝙮','𝙯'],
              'MATHEMATICAL MONOSPACE': ['𝟶','𝟷','𝟸','𝟹','𝟺','𝟻','𝟼','𝟽','𝟾','𝟿','𝙰','𝙱','𝙲','𝙳','𝙴','𝙵','𝙶','𝙷','𝙸','𝙹','𝙺','𝙻','𝙼','𝙽','𝙾','𝙿','𝚀','𝚁','𝚂','𝚃','𝚄','𝚅','𝚆','𝚇','𝚈','𝚉','𝚊','𝚋','𝚌','𝚍','𝚎','𝚏','𝚐','𝚑','𝚒','𝚓','𝚔','𝚕','𝚖','𝚗','𝚘','𝚙','𝚚','𝚛','𝚜','𝚝','𝚞','𝚟','𝚠','𝚡','𝚢','𝚣'],
              'CIRCLED': ['⓪','➀','➁','➂','➃','➄','➅','➆','➇','➈','Ⓐ','Ⓑ','Ⓒ','Ⓓ','Ⓔ','Ⓕ','Ⓖ','Ⓗ','Ⓘ','Ⓙ','Ⓚ','Ⓛ','Ⓜ','Ⓝ','Ⓞ','Ⓟ','Ⓠ','Ⓡ','Ⓢ','Ⓣ','Ⓤ','Ⓥ','Ⓦ','Ⓧ','Ⓨ','Ⓩ','ⓐ','ⓑ','ⓒ','ⓓ','ⓔ','ⓕ','ⓖ','ⓗ','ⓘ','ⓙ','ⓚ','ⓛ','ⓜ','ⓝ','ⓞ','ⓟ','ⓠ','ⓡ','ⓢ','ⓣ','ⓤ','ⓥ','ⓦ','ⓧ','ⓨ','ⓩ'],
              'NEGATIVE CIRCLED': ['⓿','❶','❷','❸','❹','❺','❻','❼','❽','❾','🅐','🅑','🅒','🅓','🅔','🅕','🅖','🅗','🅘','🅙','🅚','🅛','🅜','🅝','🅞','🅟','🅠','🅡','🅢','🅣','🅤','🅥','🅦','🅧','🅨','🅩','','','','','','','','','','','','','','','','','','','','','','','','','',''],
              'SQUARED': ['','','','','','','','','','','🄰','🄱','🄲','🄳','🄴','🄵','🄶','🄷','🄸','🄹','🄺','🄻','🄼','🄽','🄾','🄿','🅀','🅁','🅂','🅃','🅄','🅅','🅆','🅇','🅈','🅉','','','','','','','','','','','','','','','','','','','','','','','','','',''],
              'NEGATIVE SQUARED': ['','','','','','','','','','','🅰','🅱','🅲','🅳','🅴','🅵','🅶','🅷','🅸','🅹','🅺','🅻','🅼','🅽','🅾','🅿','🆀','🆁','🆂','🆃','🆄','🆅','🆆','🆇','🆈','🆉','','','','','','','','','','','','','','','','','','','','','','','','','',''],
              'PARENTHESIZED': ['','⑴','⑵','⑶','⑷','⑸','⑹','⑺','⑻','⑼','🄐','🄑','🄒','🄓','🄔','🄕','🄖','🄗','🄘','🄙','🄚','🄛','🄜','🄝','🄞','🄟','🄠','🄡','🄢','🄣','🄤','🄥','🄦','🄧','🄨','🄩','⒜','⒝','⒞','⒟','⒠','⒡','⒢','⒣','⒤','⒥','⒦','⒧','⒨','⒩','⒪','⒫','⒬','⒭','⒮','⒯','⒰','⒱','⒲','⒳','⒴','⒵'],
              'LISU': ['','','','','','','','','','','ꓮ','ꓐ','ꓚ','ꓓ','ꓰ','ꓝ','ꓖ','ꓧ','ꓲ','ꓙ','ꓗ','ꓡ','ꓟ','ꓠ','ꓳ','ꓑ','','ꓣ','ꓢ','ꓔ','ꓴ','ꓦ','ꓪ','ꓫ','ꓬ','ꓜ','','','','','','','','','','','','','','','','','','','','','','','','','',''],
              'TURNED + LISU': ['','','↊','↋','','','','','','','ꓯ','ꓭ','ꓛ','ꓷ','ꓱ','ꓞ','ꓨ','ꓧ','ꓲ','ꓩ','ꓘ','ꓶ','ꓪ','ꓠ','ꓳ','ꓒ','','ꓤ','ꓢ','ꓕ','ꓵ','ꓥ','ꓟ','ꓫ','⅄','ꓜ','ɐ','','ɔ','','ǝ','ɟ','ᵷ','ɥ','ᴉ','','ʞ','ꞁ','ɯ','','','','','ɹ','','ʇ','','ʌ','ʍ','','ʎ',''],
              'TURNED': ['','','↊','↋','','','','','','','Ɐ','','Ɔ','','Ǝ','Ⅎ','','Ɥ','','','Ʞ','Ꞁ','Ɯ','','','','','','','Ʇ','','Ʌ','','','𑾰','','ɐ','','ɔ','','ǝ','ɟ','ᵷ','ɥ','ᴉ','','ʞ','ꞁ','ɯ','','','','','ɹ','','ʇ','','ʌ','ʍ','','ʎ',''],
          };

          static replace(table, inp) {
              let out = '';
              for (const n in inp) {
                  const c = inp.charCodeAt(n) >>> 0; /*INT化のお呪い*/
                  let t = '';
                  if (0x30 <= c && c <= 0x39)
                      t = table[c - 0x30];
                  else if (0x41 <= c && c <= 0x5a)
                      t = table[c - 0x41 + 10];
                  else if (0x61 <= c && c <= 0x7a)
                      t = table[c - 0x61 + 36];
                  out += (t ? t : String.fromCharCode(c));
              }
              return out;
          }

          static convert(mode, text) {
              return ConvertAlphaNumeric.replace(
                  ConvertAlphaNumeric.TypeTable[mode],
                  text.normalize('NFKC'));
          }

          static toId(name) {
              return `AlphaNumeric ${name}`.replaceAll(' ', '_');
          }
      }

      // ----------------------------------------------------------------------

      class ConvertCircled {
          static TypeTable = {
              'CIRCLED': {
                  '0':'⓪',
                  '1':'①', '2':'②', '3':'③', '4':'④', '5':'⑤',
                  '6':'⑥', '7':'⑦', '8':'⑧', '9':'⑨', '10':'⑩',
                  '11':'⑪', '12':'⑫', '13':'⑬', '14':'⑭', '15':'⑮',
                  '16':'⑯', '17':'⑰', '18':'⑱', '19':'⑲', '20':'⑳',
                  '21':'㉑', '22':'㉒', '23':'㉓', '24':'㉔', '25':'㉕',
                  '26':'㉖', '27':'㉗', '28':'㉘', '29':'㉙', '30':'㉚',
                  '31':'㉛', '32':'㉜', '33':'㉝', '34':'㉞', '35':'㉟',
                  '36':'㊱', '37':'㊲', '38':'㊳', '39':'㊴', '40':'㊵',
                  '41':'㊶', '42':'㊷', '43':'㊸', '44':'㊹', '45':'㊺',
                  '46':'㊻', '47':'㊼', '48':'㊽', '49':'㊾', '50':'㊿',

                  'A':'Ⓐ', 'B':'Ⓑ', 'C':'Ⓒ', 'D':'Ⓓ', 'E':'Ⓔ', 'F':'Ⓕ',
                  'G':'Ⓖ', 'H':'Ⓗ', 'I':'Ⓘ', 'J':'Ⓙ', 'K':'Ⓚ', 'L':'Ⓛ',
                  'M':'Ⓜ', 'N':'Ⓝ', 'O':'Ⓞ', 'P':'Ⓟ', 'Q':'Ⓠ', 'R':'Ⓡ',
                  'S':'Ⓢ', 'T':'Ⓣ', 'U':'Ⓤ', 'V':'Ⓥ', 'W':'Ⓦ', 'X':'Ⓧ',
                  'Y':'Ⓨ', 'Z':'Ⓩ',

                  'a':'ⓐ', 'b':'ⓑ', 'c':'ⓒ', 'd':'ⓓ', 'e':'ⓔ', 'f':'ⓕ',
                  'g':'ⓖ', 'h':'ⓗ', 'i':'ⓘ', 'j':'ⓙ', 'k':'ⓚ', 'l':'ⓛ',
                  'm':'ⓜ', 'n':'ⓝ', 'o':'ⓞ', 'p':'ⓟ', 'q':'ⓠ', 'r':'ⓡ',
                  's':'ⓢ', 't':'ⓣ', 'u':'ⓤ', 'v':'ⓥ', 'w':'ⓦ', 'x':'ⓧ',
                  'y':'ⓨ', 'z':'ⓩ',

                  'CD':'🄭', 'WZ':'🄮',

                  'ア':'㋐', 'イ':'㋑', 'ウ':'㋒', 'エ':'㋓', 'オ':'㋔',
                  'カ':'㋕', 'キ':'㋖', 'ク':'㋗', 'ケ':'㋘', 'コ':'㋙',
                  'サ':'㋚', 'シ':'㋛', 'ス':'㋜', 'セ':'㋝', 'ソ':'㋞',
                  'タ':'㋟', 'チ':'㋠', 'ツ':'㋡', 'テ':'㋢', 'ト':'㋣',
                  'ナ':'㋤', 'ニ':'㋥', 'ヌ':'㋦', 'ネ':'㋧', 'ノ':'㋨',
                  'ハ':'㋩', 'ヒ':'㋪', 'フ':'㋫', 'ヘ':'㋬', 'ホ':'㋭',
                  'マ':'㋮', 'ミ':'㋯', 'ム':'㋰', 'メ':'㋱', 'モ':'㋲',
                  'ヤ':'㋳', 'ユ':'㋴', 'ヨ':'㋵',
                  'ラ':'㋶', 'リ':'㋷', 'ル':'㋸', 'レ':'㋹', 'ロ':'㋺',
                  'ワ':'㋻', 'ヰ':'㋼', 'ヱ':'㋽', 'ヲ':'㋾',

                  '一':'㊀', '二':'㊁', '三':'㊂', '四':'㊃', '五':'㊄',
                  '六':'㊅', '七':'㊆', '八':'㊇', '九':'㊈', '十':'㊉',
                  '月':'㊊', '火':'㊋', '水':'㊌', '木':'㊍', '金':'㊎', '土':'㊏',
                  '日':'㊐', '株':'㊑', '有':'㊒', '社':'㊓', '名':'㊔', '特':'㊕',
                  '財':'㊖', '祝':'㊗', '労':'㊘', '秘':'㊙', '男':'㊚', '女':'㊛',
                  '適':'㊜', '優':'㊝', '印':'㊞', '注':'㊟', '項':'㊠', '休':'㊡',
                  '写':'㊢', '正':'㊣', '上':'㊤', '中':'㊥', '下':'㊦', '左':'㊧',
                  '右':'㊨', '医':'㊩', '宗':'㊪', '学':'㊫', '監':'㊬', '企':'㊭',
                  '資':'㊮', '協':'㊯', '夜':'㊰', '問':'㉄', '幼':'㉅', '文':'㉆',
                  '箏':'㉇',

                  'ᄀ':'㉠', 'ᄂ':'㉡', 'ᄃ':'㉢', 'ᄅ':'㉣', 'ᄆ':'㉤',
                  'ᄇ':'㉥', 'ᄉ':'㉦', 'ᄋ':'㉧', 'ᄌ':'㉨', 'ᄎ':'㉩',
                  'ᄏ':'㉪', 'ᄐ':'㉫', 'ᄑ':'㉬', 'ᄒ':'㉭',
                  '가':'㉮', '나':'㉯', '다':'㉰', '라':'㉱', '마':'㉲', '바':'㉳',
                  '사':'㉴', '아':'㉵', '자':'㉶', '차':'㉷', '카':'㉸', '타':'㉹',
                  '파':'㉺', '하':'㉻', '참고':'㉼','주의':'㉽','우':'㉾',
              },
              'NEGATIVE CIRCLED': {
                  '0':'⓿',
                  '1':'❶', '2':'❷', '3':'❸', '4':'❹', '5':'❺',
                  '6':'❻', '7':'❼', '8':'❽', '9':'❾', '10':'❿',
                  '11':'⓫', '12':'⓬', '13':'⓭', '14':'⓮', '15':'⓯',
                  '16':'⓰', '17':'⓱', '18':'⓲', '19':'⓳', '20':'⓴',
                  'A':'🅐', 'B':'🅑', 'C':'🅒', 'D':'🅓', 'E':'🅔', 'F':'🅕',
                  'G':'🅖', 'H':'🅗', 'I':'🅘', 'J':'🅙', 'K':'🅚', 'L':'🅛',
                  'M':'🅜', 'N':'🅝', 'O':'🅞', 'P':'🅟', 'Q':'🅠', 'R':'🅡',
                  'S':'🅢', 'T':'🅣', 'U':'🅤', 'V':'🅥', 'W':'🅦', 'X':'🅧',
                  'Y':'🅨', 'Z':'🅩',
              },
              'DINGBAT CIRCLED': {
                  '0':'🄋',
                  '1':'➀', '2':'➁', '3':'➂', '4':'➃', '5':'➄',
                  '6':'➅', '7':'➆', '8':'➇', '9':'➈', '10':'➉',
              },
              'DINGBAT NEGATIVE CIRCLED': {
                  '0':'🄌',
                  '1':'➊', '2':'➋', '3':'➌', '4':'➍', '5':'➎',
                  '6':'➏', '7':'➐', '8':'➑', '9':'➒', '10':'➓',
              },
              'DINGBAT CIRCLED SANS SERIF': {
                  '1':'⓵', '2':'⓶', '3':'⓷', '4':'⓸', '5':'⓹',
                  '6':'⓺', '7':'⓻', '8':'⓼', '9':'⓽', '10':'⓾',
              },
          }

          static replace(table, text) {
              if (!text)
                  return text;
              const chars = [...text];
              let [last, str] = [chars.length-1, ''];
              for (let i = 0; i < chars.length;) {
                  const [c1, c2] = [chars[i], chars[i+1]];
                  const k = c1 + c2;
                  const v = table[k];
                  if (v) {
                      str += v;
                      i += k.length;
                      continue;
                  } else {
                      str += table[c1] ?? c1;
                      i += c1.length;
                  }
              }
              return str;
          }

          static convert(mode, text) {
              return ConvertCircled.replace(
                  ConvertCircled.TypeTable[mode],
                  text.normalize('NFKC'));
          }

          static toId(name) {
              return `Circled ${name}`.replaceAll(' ', '_');
          }
      }

      // ----------------------------------------------------------------------

      class ConvertParenthesized {
          static Table = {
              "1":"⑴", "2":"⑵", "3":"⑶", "4":"⑷", "5":"⑸",
              "6":"⑹", "7":"⑺", "8":"⑻", "9":"⑼", "10":"⑽",
              "11":"⑾", "12":"⑿", "13":"⒀", "14":"⒁", "15":"⒂",
              "16":"⒃", "17":"⒄", "18":"⒅", "19":"⒆", "20":"⒇",

              "A":"🄐", "B":"🄑", "C":"🄒", "D":"🄓", "E":"🄔",
              "F":"🄕", "G":"🄖", "H":"🄗", "I":"🄘", "J":"🄙",
              "K":"🄚", "L":"🄛", "M":"🄜", "N":"🄝", "O":"🄞",
              "P":"🄟", "Q":"🄠", "R":"🄡", "S":"🄢", "T":"🄣",
              "U":"🄤", "V":"🄥", "W":"🄦", "X":"🄧", "Y":"🄨",
              "Z":"🄩",

              "a":"⒜", "b":"⒝", "c":"⒞", "d":"⒟", "e":"⒠",
              "f":"⒡", "g":"⒢", "h":"⒣", "i":"⒤", "j":"⒥",
              "k":"⒦", "l":"⒧", "m":"⒨", "n":"⒩", "o":"⒪",
              "p":"⒫", "q":"⒬", "r":"⒭", "s":"⒮", "t":"⒯",
              "u":"⒰", "v":"⒱", "w":"⒲", "x":"⒳", "y":"⒴",
              "z":"⒵",

              "一":"㈠", "二":"㈡", "三":"㈢", "四":"㈣", "五":"㈤",
              "六":"㈥", "七":"㈦", "八":"㈧", "九":"㈨", "十":"㈩",
              "月":"㈪", "火":"㈫", "水":"㈬", "木":"㈭", "金":"㈮",
              "土":"㈯", "日":"㈰",
              "株":"㈱", "有":"㈲", "社":"㈳", "名":"㈴", "特":"㈵",
              "財":"㈶", "祝":"㈷", "労":"㈸", "代":"㈹", "呼":"㈺",
              "学":"㈻", "監":"㈼", "企":"㈽", "資":"㈾", "協":"㈿",
              "祭":"㉀", "休":"㉁", "自":"㉂", "至":"㉃",

              "ᄀ":"㈀", "ᄂ":"㈁", "ᄃ":"㈂", "ᄅ":"㈃", "ᄆ":"㈄",
              "ᄇ":"㈅", "ᄉ":"㈆", "ᄋ":"㈇", "ᄌ":"㈈", "ᄎ":"㈉",
              "ᄏ":"㈊", "ᄐ":"㈋", "ᄑ":"㈌", "ᄒ":"㈍",
              "가":"㈎", "나":"㈏", "다":"㈐", "라":"㈑", "마":"㈒",
              "바":"㈓", "사":"㈔", "아":"㈕", "자":"㈖", "차":"㈗",
              "카":"㈘", "타":"㈙", "파":"㈚", "하":"㈛", "주":"㈜",
              "오전":"㈝", "오후":"㈞",
          }

          static replace(text) {
              return text.replace(/(\([^()]+\))/g, ((_, p) =>
                  ConvertParenthesized.Table[p.slice(1, p.length - 1)] ?? p));
          }
      }

      // ----------------------------------------------------------------------

      function toClipboard(text) {
          navigator.clipboard.writeText(text).then(() => {
              // success
          }, () => {
              // failed
          });
      }

      function onInput(text) {
          lastText = text;

          if (lastMode == 'Normalize') {
              const C = NormalizeDiff;
              C.TypeTable.forEach(name => document.getElementById(C.toId(name)).innerHTML = new C(name, text).toHTML());
              return;
          }
          if (lastMode == 'InnerHTML') {
              InnerHTML_output.innerHTML = text;
              return;
          }
          if (lastMode == 'CodePoint') {
              const C = CodePointRuby;
              const gen = new C(text);
              C.TypeTable.forEach(name => document.getElementById(C.toId(name)).innerHTML = gen.toHTML(name));
              return;
          }
          if (lastMode == 'AlphaNumeric') {
              const C = ConvertAlphaNumeric;
              Object.keys(C.TypeTable).forEach(name =>
                  document.getElementById(C.toId(name)).innerText = C.convert(name, text));
              return;
          }
          if (lastMode == 'Circled') {
              const C = ConvertCircled;
              Object.keys(C.TypeTable).forEach(name =>
                  document.getElementById(C.toId(name)).innerText = C.convert(name, text));
              return;
          }
          if (lastMode == 'Parenthesized') {
              Parenthesized_output.innerHTML = encodeHTML(ConvertParenthesized.replace(text));
              return;
          }
      }

      function onClick(mode) {
          OutputTable.forEach(name =>
              document.getElementById(name).hidden = (name != mode));
          lastMode = mode;
          onInput(lastText);
      }

      window.onload = function() {
          const gentab = ((C, O, tab, button, nfilter) => {
              tab.forEach(name => {
                  const id = C.toId(name);
                  const thn = (!nfilter ? name : nfilter(name)).replaceAll(' ', '&nbsp;');
                  const tht = !button ? thn : `<button onclick="toClipboard(${id}.innerText)">${thn}</button>`;
                  O.insertAdjacentHTML('beforeend', `<tr><th class="left">${tht}</th><td id="${id}"></td></tr>`);
              });
          });

          gentab(CodePointRuby, CodePoint, CodePointRuby.TypeTable);
          gentab(NormalizeDiff, Normalize, NormalizeDiff.TypeTable, true);
          gentab(ConvertAlphaNumeric, AlphaNumeric,
                 Object.keys(ConvertAlphaNumeric.TypeTable), true,
                 n => n.replace('MATHEMATICAL ', 'MATHEMATICAL<br/>'));
          gentab(ConvertCircled, Circled, Object.keys(ConvertCircled.TypeTable), true);

          onClick(OutputTable[0]);
      }

    </script>
  </body>
</html>
```

</div></details>