とある仕事で、運営しているWebサービスのテキスト原稿のプレビュー表示を作っていた所、
タブ、全角スペース、半角スペースというテキストエディタであれば、目視できるように、プレビュー表示でこれらを目で見て判別できるようにして欲しいというオーダーをいただきました。
そのオーダーを聞いて、単純に文字列を置換すればいいだけだと軽く考えていたんですが、オーマイガ!
なんと、その原稿は、HTML書式で中にHTMLタグがたくさん書き込まれていたのでした。
これの何が問題で、どう対応したのかを、ブログに書き残しておきます。
安心してください、ちゃんと解決しましたよ。
問題点
タブと全角スペースはさほど問題ではないんですが、半角スペースがとにかく問題点でした。
HTMLタグの中にも半角スペースが混在しているので、単に置換してしまうと、とんでもない変換結果になってしまうという事が後で気がついたんですよね。
※実際にコード書いてみて、結果で理解しました・・・アホ・・・
全角スペースは、HTMLタグに書き込むのはご法度なので置換してもいいかと思うんですが、実はタブ文字列も、HTMLに書き込むことは仕様上ありえるので、こりゃあタグ以外の文字列に対して置換処理を行う対応が必要だと思ったんですね。
ちなみに、原稿ではないですが、下記のような感じの文字列が対象になります。
文字列に<span style="color:red">HTMLタグ</span>が入るよ
解決法
DOM操作deNode種別を理解している人ならさほど難しい対応ではないと思いますが、以下のようなスニペットを作ってみました。
function replaceSpacesInTextNodes(element, searchValue, replaceValue) {
// 指定された要素の全ての子要素を走査する
element.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
// テキストノードの場合、指定された置換を行う
node.textContent = node.textContent.replace(new RegExp(searchValue, 'g'), replaceValue);
} else {
// 子要素がある場合、再帰的に処理する
replaceSpacesInTextNodes(node, searchValue, replaceValue);
}
});
}
// 使用例
document.addEventListener("DOMContentLoaded", () => {
// HTML全体を対象にする場合はdocument.bodyを渡す
replaceSpacesInTextNodes(document.body, ' ', '置換後の文字列');
});
解説
replaceSpacesInTextNodes()という関数に、変換したい文字列の親要素と、置換対象の文字列と、置換後の文字列を送ると、text-nodeのみの文字列を置換するというスニペットです。
ちなみに、データベースから取得したての場合に、HTMLが要素になっておらず、文字列の場合は、次のようにすると対応できます。
// textにHTML文字列が入っている状態。
const div = document.createElement("div")
div.innerHTML = text
replaceSpacesInTextNodes(div, ' ', '置換後の文字列');
少し改良すれば、複数の置換処理に対応させたり、特定のHTMLタグ内だけなどの処理もできそうです。
あとがき
きっと今後自分で使うだろうな・・・という処理だったので、ブログに残しておきました。
簡易に考えたら、正規表現とかで何とかしようと思いがちですが、今回のソースを使うと、多重階層であっても対応できるので、結構精度がいいと思いますよ。
いや〜仕事をすればするほど、自分スニペットが溜まっていくのは、なかなか良い感じの積立ですな〜。
参考サイト
ちなみに、以下のサイトに全く同じソースを載せておきました。(自分用備忘録サイトなのです)
https://www.tech-memo.com/2024/07/javascript-html.html
0 件のコメント:
コメントを投稿