0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

小道具: String.normalize 結果の可視化

Last updated at Posted at 2023-03-19

概要

文字列の変換メソッド normalize() によって変更される文字の背景色を変更して可視化します。

文字コード確認では「小道具:rubyタグを使って文字の上にコードを出力」を用意しています。

See the Pen String.normalize メソッドのテスト by Ikiuo (@ikiuo) on CodePen.

ソースコード

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>String.normalize 結果の可視化</title>
  </head>
  <body>
    <script>

      const NormalizeTable = ['NFC', 'NFD', 'NFKC', 'NFKD'];

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

      function stringToChars(mode, inp) {
          return [...inp].map((c) => {
              const n  = c.normalize(mode);
              return { chk:(c == n), inp:c, out:n }
          });
      }

      function checkComposite(mode, inp, start, end) {
          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;
      }

      function checkNormalize(mode, inp) {
          if (!inp)
              return '';

          const chars = stringToChars(mode, inp);
          let pos = 0;
          let end = chars.length;
          while (pos < end)
              pos += checkComposite(mode, chars, pos, end);

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

      function onInput(text) {
          NormalizeTable.forEach((m) =>
              document.getElementById(m)
                  .innerHTML = checkNormalize(m, text));
      }

      // 要素生成は CodePen のトラブル対策.
      window.onload = function() {
          document.body.innerHTML = [
              '<table border="1">',
              '<tr><th>入力</th><td>',
              '<textarea rows="6" cols="80" oninput="onInput(this.value)"></textarea>',
              '</td></tr>',
              NormalizeTable.map((v, n) => `<tr><th>${v}</th><td id="${v}"></td></tr>`),
              '</table>',
          ].flat().join('');
      }

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

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?