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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Gmail

GmailとはGoogleによって提供されているウェブメールのサービスのことです。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

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

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

Q&A

2回答

1681閲覧

Javascriptの置換を、長い単語から行うようにしたい。

Beginner3

総合スコア14

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Gmail

GmailとはGoogleによって提供されているウェブメールのサービスのことです。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

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

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

0グッド

0クリップ

投稿2020/01/22 09:05

編集2020/02/17 14:41

現在、Gmailで添付した画像からOCRでテキストを取得し、そのテキスト内の単語と、事前に設定したスプレッドシートの単語とURLのリストで一致するものを置換し、返信するところまでは出来ます。

しかし、「東京」「東京都」「東京都知事」といった単語をリストに設定し、置換した際に「東京都知事」で置換されず「東京」のみがハイパーリンクに置換されるようになっています。

スプレッドシートのリストを文字列の長さ順に並び替えたので、これを上から順番に置換するようにできれば「東京都知事」になるのではないかと考えたのですが、その方法がわかりません。上から順番に置換するよう設定する以外の方法でも、目的が達成可能なものでしたら構いません。

また、一度「東京」で置換を行うと、その後「東京」の文字列があっても置換が行われなくなります。この問題を解決することは可能でしょうか。

イメージ説明
添付画像 この画像をGmailに添付して送信する


イメージ説明

単語リスト 置換したい単語とURLを文字列の長さ順でスプレッドシートに


イメージ説明

置換結果 「東京都知事」で置換されず、「東京」のハイパーリンクのみ。また、それ以後の「東京都知事」「東京都」「東京」の文字も置換できない結果となる。置換が行われると単語の前後にスペースができることから、おそらくハイパーリンクとして表示されている「東京」だけでなく「東京都知事」「東京都」としても置換処理が行われたために、それ以後もできなくなっている。

 

イメージ説明

追記画像  回答のアドバイスのおかげで「東京都知事」で置換されるようになりました。最初の単語以降はできない。


イメージ説明

理想の置換結果 長い単語を短い単語で分割することなく、すべての単語が置換されるようにしたい。


Google

1 2function parseGmail() 3{ 4 var ss = SpreadsheetApp.getActiveSpreadsheet(); 5 var sheet = ss.getSheetByName('シート1'); 6 var settings = ss.getSheetByName('設定'); 7 8 var recipient = settings.getRange('A2').getDisplayValue(); 9 var senderName = settings.getRange('B2').getDisplayValue(); 10 var receivedFrom = settings.getRange('C2').getDisplayValue().trim(); 11 12 var body1 = settings.getRange('A4').getDisplayValue(); 13 var body2 = settings.getRange('B4').getDisplayValue(); 14 var subject = settings.getRange('C4').getDisplayValue(); 15 16 17 var val = sheet.getDataRange().getDisplayValues(); 18 var threads = GmailApp.search('from:'+receivedFrom+' has:attachment newer_than:1d; is:unread'); 19 var param = { 20 title: 'OCR File', 21 mimeType: 'image/png' 22 }; 23 var arr = ''; 24 for(var i in threads) 25 { 26 var messages = threads[i].getMessages(); 27 for(var j in messages) 28 { 29 var attachments = messages[j].getAttachments(); 30 for(var k in attachments) 31 { 32 var file = attachments[k]; 33 var type = file.getContentType(); 34 if(type.match('image')) 35 { 36 var OCR = file.copyBlob(); 37 var textDoc = Drive.Files.insert(param, file, {ocr: true}); 38 var url = textDoc.alternateLink; 39 var doc = DocumentApp.openByUrl(url); 40 var id = doc.getId(); 41 var text = doc.getBody().getText(); 42 doc.saveAndClose(); 43 Drive.Files.remove(id); 44 text = text.replace(/\n/g, '').replace(/\s/g, ''); 45 var ret = ProcessText(val, text); 46 if(ret !== false) 47 { 48 var body = body1 + ret +body2; 49 body = body.trim(); 50 MailApp.sendEmail( 51 { 52 to: recipient, 53 subject: subject, 54 name: senderName, 55 htmlBody: body 56 }) 57 } 58 } 59 } 60 messages[j].markRead(); 61 } 62 } 63} 64 65 66function ProcessText(val, text) 67{ 68 try 69 { 70 var ahref = '<a href="#URL#" target="blank">'; 71 var newText = text; 72 for(var i in val) 73 { 74 var word = val[i][0].toString().toUpperCase(); 75 var check = newText.match(word); 76 if(check !== null) 77 { 78 var Url = val[i][1]; 79 newText = newText.replace(word, ' <a href="'+Url+'" target="blank">' +word+ '</a> '); 80 } 81 } 82 return newText.trim(); 83 } 84 catch(err) 85 { 86 return false; 87 } 88}

イメージ説明
補足:タイムアウトしている様子

g

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

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

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

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

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

guest

回答2

0

javascript

1function q236809() { 2 const str = '東京都知事が東京都の財政について、道知事や府知事、特に大阪府知事と東京のある場所で語った。'; 3 const arr = [["東京都知事","tky_chiji"],["東京都","tky_metro"],["東京", "tky"],["大阪府知事","osk_chiji"],["大阪府","osk_metro"],["府知事", "fuchiji"], ["、", "punct"]]; 4 Logger.log(ProcessText(arr, str)); 5} 6function ProcessText(val, text) 7{ 8 const dic = val.reduce(function (a,c) { 9 a[c[0]] = c[1]; 10 return a; 11 },{}); 12 var poses = toPos(text); 13 Object.keys(dic).forEach(function (e) { getPoses(text,e).forEach(function (f) { if(poses[f] < f + e.length) { poses[f] = f + e.length;}})}); 14 var cursor = 0; 15 var ret = ""; 16 for(var s = 0; s < poses.length;) { 17 var e = poses[s]; 18 if (s === e) { s++; continue;} 19 var needle = text.substring(s,e); 20 ret += text.substring(cursor,s) + anchor(needle, dic[needle]); 21 cursor = e; 22 s = e; 23 } 24 ret += text.substring(cursor); 25 return ret; 26} 27function anchor(word, url) { 28 return ' <a href="'+url+'" target="blank">' +word+ '</a> '; 29} 30function toPos(str) { 31 return str.split("").map(function(_,i){ return i;}); 32} 33function getPoses(haystack, needle) { 34 var ret = []; 35 var pos = haystack.indexOf(needle); 36 const len = needle.length; 37 while (pos !== -1) { 38 ret.push(pos); 39 pos = haystack.indexOf(needle, pos + len); 40 } 41 return ret; 42}

ProcessText を作り直しました。ついでに補助関数を定義。
q2368089() で検証。
arrが、シートに書いてあるキーワードのサンプル。str は置換対象の文章。
想像している要件は、同じワードがくりかえし出現しても対応する、マッチする範囲が重複したとき、先に開始し他のワードに包含されないものを採用する、ということ。
例えば、東京都立と都立大学がキーワードとしてあったとき、このコードだと、東京都立が優先する。この辺どうなんでしょう。要件が不明でした。なお、このコードだと後者が都立航空高専であっても、東京都立を優先してしまう。だからロンゲストマッチですらない。

今回は、データを加工できるとわからない(それは回答者には決められないから)状態で加工せずに解決できそうな方法として提示しました。

で、こういう面倒なコードをかくより、そのシートで東京都知事と東京都と東京は同じurlであるか、もしくは、東京都知事と東京都と東京が同じグループなんだということをC列にグルーピング順位として持たせて、同じグループなら、より文字の長いものを優先することにすれば、質問者様の ProcessText のループをいじるだけでできそう(できるとは言ってない)。データにグルーピングおよびグルーピングが順位として表現されていれば東京都立と都立航空高専の優先度を人間の意図どおり表現できる。

投稿2020/01/22 09:23

編集2020/01/22 14:43
papinianus

総合スコア12705

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

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

Beginner3

2020/01/22 12:03 編集

回答ありがとうございます!追記画像のように「東京都知事」で置換されるようになりました。 ただ、最初の単語のみで終わってしまうので、それ以降の単語も置換をするにはどうすればよいでしょうか。
papinianus

2020/01/22 10:31

あーそれ考えてなかったです。 ちょっと時間かかるかも。考えてみます。
Beginner3

2020/01/23 08:37

ありがとうございます。q2368089()を実際に使う際の単語に置き換えて検証したところ、ほとんど理想の形で置換されるようになりました! また、手取り足取り教えていただいてさらに質問するのは恐縮ですが、作り直していただいたProcessTextに置き換えると、作動しなくなり、色々いじっては見たもののGmailで返信させることはできませんでした。どこを修正すれば良いか見当つきますでしょうか。
papinianus

2020/01/23 08:41

作動しない、といえのは具体的には、エラーがないけどメールが送られない、ということですか?もうちょっとヒントください。 既存のProcessTextを消した上で、qで始まらない4つの関数を全てコピーして、貼り付ける操作を想定しています。3つが足りてなかったらエラーになるのでこの説は外していると想定
Beginner3

2020/02/17 14:42 編集

既存のProcessTextを削除し、最初のq2368089()以外の関数を貼り付けるところまでは出来ていると思います。
papinianus

2020/01/24 14:31

作動しない、を具体的に教えてください。 拝見しましたが、その貼り付けで想定しているとおりです。 あと、parseGmail のループの中で ProcessText を実行している直前で、val と text に想定のデータが入っているか、Logger.log() を実行するなどしてご確認いただけませんか。
Beginner3

2020/01/25 06:22

実行すると全てタイムアウトになり、エラーは出ませんがメールは返信されません。Gmailに添付画像を含む未読メールがない際にはタイムアウトにはなりません。
papinianus

2020/01/25 06:25 編集

ちなみに対象のメールは何通でしょう?メール全体の件数の規模感と添付があるメールの件数の規模感をしりたいです。 あと、以前のコードではタイムアウトになってなかったことを念の為確認したいです。
Beginner3

2020/01/25 06:47

検証専用のメールアドレスで行っているので、1枚の添付画像を含む未読メールは一通のみです。既読メールは50通ほどあります。たった今以前のコードで試しましたが、7.171 秒で終了し返信されました。
guest

0

Javascriptの置換を、長い単語から行うようにしたい。

置換処理の直前でソートしてはいかがでしょう?

二重配列

javascript

1var samples = [["a","rep1"],["abc","rep2"],["ab","rep3"]]; 2samples.sort((a,b)=> b[0].length-a[0].length); 3console.log( samples ); 4// [["abc","rep2"],["ab","rep3"],["a","rep1"]]

また、置換は、正規表現を使うと早いかと思います

dst = src; for( let [w, r] of samples ) { dst = dst.replace( new RegExp(w,"g"), ()=>anchor(w,r) ); }

追記)
ごめんなさい。
置換処理はテキストの例で回答をしてしまっていました。
スプレッドシートの場合も「直前のソート」は応用できるかと思います。

投稿2020/01/23 21:20

編集2020/01/23 21:28
AkitoshiManabe

総合スコア5432

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問