WebKitにrubyタグのレンダリングのサポートが入ったので、新聞社のサイトなどで狡猾(こうかつ)な犯行
などと書いてあるものをrubyタグで包むスクリプトを書いた。
// console.time("benchmark"); var r = document.evaluate( './/text()[contains(., "(")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); var i; var node; var re = /(.*?)([一-龠]+)(([ーぁ-んァ-ヶ]+))/g; var match; var range = document.createRange(); var text; for (i = 0; i < r.snapshotLength; i++) { node = r.snapshotItem(i); text = node.textContent; if (!re.test(text)) { continue; } range.selectNode(node); node.parentNode.replaceChild( range.createContextualFragment( text.replace(re, "$1<ruby>$2<rp>(</rp><rt>$3</rt><rp>)</rp></ruby>") ), node ); } range.detach(); // console.timeEnd("benchmark");
createContextualFragmentやinnerHTMLを使うとこのようにシンプルに書けるが大量にマッチする場合速度が少し落ちる。
で、これを使わないと見ての通り急に複雑になる。ただし、速度は少し上がる。
// console.time("benchmark"); var r = document.evaluate( './/text()[contains(., "(")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); var i; var node; var re = /([一-龠]+)(([ーぁ-んァ-ヶ]+))/g; var match; var left; var fragment; var text; for (i = 0; i < r.snapshotLength; i++) { node = r.snapshotItem(i); text = node.textContent; fragment = document.createDocumentFragment(); if (!re.test(text)) { continue; } re.lastIndex = 0; left = 0; while ((match = re.exec(text))) { fragment.appendChild( document.createTextNode(text.slice(left, re.lastIndex - match[0].length)) ); fragment.appendChild(createRuby(match[1], match[2])); left = re.lastIndex; } fragment.appendChild( document.createTextNode(text.slice(left)) ); node.parentNode.replaceChild(fragment, node); } function createRuby(text, annotation) { var ruby = document.createElement("ruby"); var rp1 = document.createElement("rp"); var rt = document.createElement("rt"); var rp2 = document.createElement("rp"); rp1.appendChild(document.createTextNode("(")); rt.appendChild(document.createTextNode(annotation)); rp2.appendChild(document.createTextNode("(")); ruby.appendChild(document.createTextNode(text)); ruby.appendChild(rp1); ruby.appendChild(rt); ruby.appendChild(rp2); return ruby; } // console.timeEnd("benchmark");