実現したいこと
- HTML内にある特定の文字列を全て置換する
- この時、置換してほしくない部分(URL)を対象外にする
前提
自動翻訳の精度を上げるため、固有名詞を先に日本語に置き換えるChrome拡張機能を作っています。
以下のコードである程度は目的通りに動作するのですが、<a href=>や<img src=>などのURLまで書き換えてしまうので、これを修正したいです。
該当のソースコード
JavaScript
1const api_url = 'https://スプレッドシートのAPI'; //[{"日a1":"あ","英a1":"A","中a1":"亜","日b1":"ア",,,},{"日a2":"い",,,},,,] 2 3(async function() { 4 nameDB = await (await fetch(api_url)).json(); //APIの取得(async-await辺り)はコピペ 5 6 for (var i = 0; i < Object.keys(nameDB).length; i++) { 7 getText = document.querySelectorAll('div > :not(script)'); //置換対象をタグで指定 8 9 nameA = new RegExp(nameDB[i].aEng + '|' + nameDB[i].aChn, 'g'); //まとめて置換するため正規表現/aEng|aChn/gに変換 10 nameB = new RegExp(nameDB[i].bEng + '|' + nameDB[i].bChn, 'g'); 11 nameC = new RegExp(nameDB[i].cEng + '|' + nameDB[i].cChn, 'g'); 12 nameD = new RegExp(nameDB[i].dEng + '|' + nameDB[i].dChn, 'g'); 13 14 for(var j = 0; j < getText.length; j++){ 15 getText[j].innerHTML = getText[j].innerHTML.replace(nameA, nameDB[i].aJpn); 16 getText[j].innerHTML = getText[j].innerHTML.replace(nameB, nameDB[i].bJpn); 17 getText[j].innerHTML = getText[j].innerHTML.replace(nameC, nameDB[i].cJpn); 18 getText[j].innerHTML = getText[j].innerHTML.replace(nameD, nameDB[i].dJpn); 19 } 20 } 21})()
試したこと
- querySelectorAllの条件に :not([href]) や :not([src]) を追加
→変化なし - querySelectorAllの条件を (h1, h2,,,) のようにタグを一つ一つ指定
→置換が過剰/不足のどちらかになる - getText[j].childrenで子要素を取得して配列に変換し、tagNameを基準に除外(下記コード)
→変化なし、対象が奥深くにあることが原因?
JavaScript
1//14~19行目と入れ替え 2for(let j = 0; j < getText.length; j++){ 3 const matchTags = Array.prototype.filter.call(getText[j].children, function (elem) { 4 return elem.tagName === 'A' || elem.tagName === 'IMG'; //子要素を配列化してtagNameで抽出 5 }); 6 if (matchTags.length === 0){ //子要素にaタグ、imgタグがない場合だけ実行 7 /* (innerHTML.replace) */ 8 } 9}
修正後のコード
需要は少なさそうですが、一応今回の最終的なコードを残しておきます。
JavaScript
1const api_url = 'スプレッドシートのAPI'; //[{"jpn0":"","eng0":"","chn0":"","jpn1":"",,,},{"jpn0":"",,,},,,]の形に変更 2 3(async function() { 4 nameDB = await (await fetch(api_url)).json(); 5 for (let i = 0; i < Object.keys(nameDB).length; i++) { 6 let walkerText= document.createTreeWalker( 7 document.body, 8 NodeFilter.SHOW_TEXT,function(node){ 9 if(node.data.match(/\S/g)){ //ホワイトスペースなどの不必要な検索対象を除外し高速化 10 return NodeFilter.FILTER_ACCEPT; 11 }else{ 12 return NodeFilter.FILTER_REJECT; 13 } 14 } 15 ); 16 while(true){ 17 tgt2Repl = walkerText.nextNode(); 18 if(tgt2Repl === null){ //nextNode() が null の時 = 全てのノードの処理が完了した時 19 break; 20 }; 21 for(let j = 0; j < 4; j++){ 22 engElem = eval('nameDB[i].eng' + j); //evalは脆弱性の関係で非推奨とのこと。今回は個人的な拡張機能ということで採用 23 if(engElem !== ''){ //元のAPIの構造上空白の辞書があるためここで弾く 24 chnElem = eval('nameDB[i].chn' + j); 25 jpnElem = eval('nameDB[i].jpn' + j); 26 flElem = new RegExp(engElem + '|' + chnElem, 'g'); 27 if(tgt2Repl.data.includes(engElem) || tgt2Repl.data.includes(chnElem)){ 28 tgt2Repl = tgt2Repl.data.replace(flElem, jpnElem); 29 }; 30 }; 31 }; 32 }; 33 }; 34})()
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/04/08 04:40