質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Chrome extension

Chrome拡張機能

Q&A

解決済

2回答

1356閲覧

JS(Chrome拡張機能) HTML中の任意の文字列を、URLを除き全て置換したい

strauzer

総合スコア1

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Chrome extension

Chrome拡張機能

0グッド

1クリップ

投稿2023/04/05 15:15

編集2023/04/08 05:13

実現したいこと

  • 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})()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

表示上の文字を変更したいだけならテキストノードを抽出し値を変更すればいいでしょう。
あとはテキストに埋め込まれているURLがあった場合どうしたいかによります
具体的なサンプルデータがあれば指摘しやすいと思います

投稿2023/04/06 04:56

yambejp

総合スコア114843

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strauzer

2023/04/08 04:40

まさしくテキストノードを活用することで解決できました! テキストのURL(ハイパーリンク化されていないURLという認識であっていますか)の事は完全に盲点でした。 幸い、今回の場合は考慮せずとも大丈夫そうでしたが、サンプルデータを提示する重要性を知る良い機会になりました。 次に質問する機会があれば気をつけたいと思います。 ありがとうございました!
guest

0

ベストアンサー

innerHTML を対象に置換を行うのは止めたほうがよいでしょう。子ノードが置き換えられて多くのページが動かなくなるはずです。

NodeFilter.SHOW_TEXT を指定した TreeWalkerText ノードを列挙し、data プロパティを置換しましょう。node.parentNode.closest('script, style') などで特定要素下のテキストをチェックできます。

投稿2023/04/05 22:15

int32_t

総合スコア20884

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strauzer

2023/04/08 04:29

ご教示いただいた方法で、思っていた通りにうまく置換することができました。 ホワイトスペースが検索対象になることで動作が重くなる問題に少し悩まされましたが、なんとかクリアし無事快適に動作するようになりました。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問