概要
文字列の変換メソッド 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 = { '<':'<', '&':'&', '>':'>', '\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>
参考