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

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

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

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

Gmail

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

Google Apps Script

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

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Q&A

解決済

3回答

1946閲覧

【GAS】Gmailの本文を取得した後、正規表現を削除してスプレッドシートへ転記したい

shz4x4

総合スコア5

Google スプレッドシート

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

Gmail

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

Google Apps Script

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

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

0グッド

1クリップ

投稿2021/09/19 16:30

編集2021/09/20 02:23

前提・実現したいこと

GAS(Google Apps Script)を使用してGmailの本文を取得した後、正規表現を削除してスプレッドシートへ転記したい。

<前提>
・重複して転記することを防ぐため、「転記済み」ラベルの付いていないメールのみを抽出する。
・スレッド内のすべてのメールを転記すると煩雑になるため、最初のメールのみ転記する。
・メールは本文に以下のような内容が記載されているものとする。

  (メール本文)
お名前:山田太郎
住所:東京都千代田区

発生している問題・エラーメッセージ

エラー
TypeError: Cannot read property '0' of undefined
myFunction @ コード.gs:19

#該当のソースコード

GAS

1function myFunction() { 2 3 const query = 'in:inbox -label:転記済み'; 4 const start = 0; 5 const max = 10; 6 7 const threads = GmailApp.search(query,start,max); 8 const messagesForThreads = GmailApp.getMessagesForThreads(threads); 9 10 const label = GmailApp.getUserLabelByName('転記済み') || GmailApp.createLabel('転記済み'); 11 12 for(const messages of messagesForThreads){ 13 const message = messages[0]; 14 15  //var regName = new RegExp(/お名前: (.*)/); 16 //var regAdress = new RegExp(/住所: (.*)/); 17 //以下に修正 18 var regName = new RegExp(/お名前:(.*)/); 19 var regAdress = new RegExp(/住所:(.*)/); 20 21 const plainbody = message.getPlainBody(); 22 23 //const Name = plainbody.match(regName).replace[0]('お名前:',''); 24 //以下に修正 25 26 const Name = plainbody.match(regName)[0].replace('お名前:',''); 27 28  //const Adress = plainbody.match(regTel)[0].replace('住所:',''); 29  //以下に修正 30 31 const Adress = plainbody.match(regAdress)[0].replace('住所:',''); 32 const from = message.getFrom(); 33 const date = message.getDate(); 34 35 const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('メール転記'); 36 const lastrow = sheet.getLastRow() + 1; 37 38 sheet.getRange(lastrow,1).setValue(from); 39 sheet.getRange(lastrow,2).setValue(date); 40 sheet.getRange(lastrow,3).setValue(Name); 41 sheet.getRange(lastrow,4).setValue(Adress); 42 43 message.getThread().addLabel(label); 44 45 } 46} 47

#試したこと
初学者のため、ネット上の情報を参考にコードを作成しています。
エラーメッセージから、正規表現に関するエラーと思いますが、
正規表現部分(15〜16行目)を修正しても同様のエラーが発生してしまいます。

ご教示いただけますと幸いです。
よろしくお願いします。

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

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

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

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

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

guest

回答3

0

ベストアンサー

(上乗せとなりすみませんが、質問者さんから回答依頼が来たので回答します)


※【注意】
下記は、
・メール中の住所・名前の隣のコロンが全角(「:」)、
・「住所:」や「お名前:」の出現箇所が1か所だけ、
・「住所:」や「お名前:」の行いずれも末尾では改行されている
・「住所:」「お名前:」の行の改行までは、住所や名前以外のデータがない
ということが前提です。

この前提から外れる場合は、下記のコードでは期待した結果が得られない可能性があります。


 

文字列.match(RegExpオブジェクト)

とすると
・文字列内にマッチするパターンがある場合は、その部分が配列として返ってきます。
・マッチしない場合は、nullが返ってきます。

たとえば、

txt1 ="お名前:山田太郎"; txt2 ="ダミーテキスト"; const regName = new RegExp(/お名前:(.*)/); const name1 = txt1.match(regName) const name2 = txt2.match(regName) Logger.log("name1=" + name1); Logger.log("name2=" + name2);

として、実行すると

出力結果 name1= [お名前:山田太郎, 山田太郎]  ・・・・(1) name2= null ・・・・(2)

という結果になります。

(1)のように、
RegExpオブジェクト内に括弧で囲んだグループの指定「(.*)」があってマッチする場合は
「1番目にマッチした部分全体(「お名前:山田太郎」)、2番目にグループのマッチした部分(「山田太郎」)」
が配列として返ってくることが分かります。

したがって、(.*)に該当する部分は、「name1[1]」とすれば抜き出せます。

txt2はマッチするものがないのでnullが返ってきています。

上記を元にコードを書きなおすと下記のようになります。

※sheetの取得やRegExpオブジェクトの設定は、ループ前に一度行えばよいので、ループ前に移動しています。

js

1function myFunction() { 2 3 const query = 'in:inbox -label:転記済み'; 4 const start = 0; 5 const max = 10; 6 7 const threads = GmailApp.search(query,start,max); 8 const messagesForThreads = GmailApp.getMessagesForThreads(threads); 9 10 const label = GmailApp.getUserLabelByName('転記済み') || GmailApp.createLabel('転記済み'); 11 12 const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('メール転記'); 13 14 const regName = new RegExp(/お名前:(.*)/); 15 const regAdress = new RegExp(/住所:(.*)/); 16 17 for (const messages of messagesForThreads) { 18 const message = messages[0]; 19 const from = message.getFrom(); 20 const date = message.getDate(); 21 const plainbody = message.getPlainBody(); 22 23 const Name = plainbody.match(regName); 24 const Adress = plainbody.match(regAdress); 25 26 // 名前・住所いずれかがマッチしない場合は、スキップする 27 if (Name == null || Adress == null) continue; 28 29 const lastrow = sheet.getLastRow() + 1; 30 sheet.getRange(lastrow,1).setValue(from); 31 sheet.getRange(lastrow,2).setValue(date); 32 sheet.getRange(lastrow,3).setValue(Name[1]); 33 sheet.getRange(lastrow,4).setValue(Adress[1]); 34 35 message.getThread().addLabel(label) 36 37 } 38} 39

投稿2021/09/20 03:07

編集2021/09/20 04:57
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

shz4x4

2021/09/20 03:45

早急に回答いただき誠にありがとうございます。 いただいた回答を拝見し、理解いたしました。 一点、追加でご教示いただけないでしょうか。 前提として、「ご住所:」「名前:」の行の改行までに、何らかの文字列が記入されていた場合に、 所望の処理を行うにはどういった手段があるのでしょうか。 お手数をおかけし申し訳ありませんがよろしくお願いいたします。
退会済みユーザー

退会済みユーザー

2021/09/20 05:01 編集

すみませんが[「住所:」「お名前:」の行の改行までに、何らかの文字列が記入されていた場合] の具体例を教えてください。 自分が書いたコードは、たとえば 「 お名前:田中太郎 住所:○○県○○市1-1-1 注文明細:商品番号111 商品名○○ ありがとうございました。 」 のように、"各行のコロンの後から改行まで"に、名前や住所以外のデータがない限り、正常に動くものとして確認しています。 (別の行に何か余計なデータがあっても、その部分は別の行なので無視されます) しかしたとえば、名前以外のデータが”同じ行”にあると、そのデータまで抜き取ってしまいます。 たとえばメール本文が 「 お名前:田中太郎  ニックネーム:taro111 住所:○○県○○市1-1-1  電話番号:090-***-**** 注文明細:商品番号111 商品名○○ ありがとうございました。 」 のような場合だと、私の書いたコードでは Name[1]は「田中太郎  ニックネーム:taro111」 Adress[1]は「○○県○○市1-1-1  電話番号:090-***-****」 となってしまいます。 質問者さんがおっしゃっている[「住所:」「お名前:」の行の改行までに、何らかの文字列が記入されていた場合]というのは、上記のような場合なのでしょうか。 違うのであれば、具体例を教えてください。
shz4x4

2021/09/20 04:52

ありがとうございます。 例えば、以下の場合で試したところ、正規表現部分が削除されず、 正規表現部分も含めてスプレッドシートへ転記されていましました。 「 こんにちは。 田中です。 お世話になっております。 名前:田中太郎 ご住所:○○県○○市1-1-1 」
退会済みユーザー

退会済みユーザー

2021/09/20 05:00 編集

すみません、回答内の例文と回答内の実際のコードが一部異なる部分があったため、回答内の例文を修正しました。 元々の質問には 「お名前:(名前) 住所:(住所) 」 というパターンが記載されていたので、それを抜き出すようにコードを書いています。 そのコメントだと 「名前: ご住所:」 になっているので、マッチするものがありません。 抜き出す対象のメールは 「お名前: 住所:」 と 「名前: ご住所:」 どちらなのでしょうか? もし後者ならば、それに合わせて、RegExpの中身を書き換える必要があります。
shz4x4

2021/09/20 05:05

すみません。 コメントの誤記です。 対象メール内の記載は、 「お名前: 住所:」 でした。 誤記によりお手数をおかけし申し訳ありません。
退会済みユーザー

退会済みユーザー

2021/09/20 05:14

確認させてください。 1.まず、回答欄のコードをそのままGASのエディタにコピペして保存してください。 2.次に 「 こんにちは。 田中です。 お世話になっております。 お名前:田中太郎 住所:○○県○○市1-1-1 」という内容のメールを自分宛にテスト送信してみてください。 3.さきほどのコードを実行してください。 この場合でも、うまく抜き出せない(全部抽出されてしまう)、ということでしょうか?
shz4x4

2021/09/20 05:21

指示いただいたとおりに進めた結果、うまくいきました。 コードを比較したところ、以下2文の[1]が抜けておりました。 ケアレスミスによりお手数をおかけし申し訳ありません。 この度は丁寧にご対応いただき、大変勉強になりました。 ありがとうございました。 sheet.getRange(lastrow,3).setValue(Name[1]); sheet.getRange(lastrow,4).setValue(Adress[1]);
退会済みユーザー

退会済みユーザー

2021/09/20 05:42 編集

間違いやすいところですね。 (1個前の質問に対する回答のように、diffで色分けした方が分かりやすかったかもしれません・・・) 解決してよかったです。
guest

0

もう一つイージーミスを22行目で見つけました。以下になります。
regTelは定義されておらず、regAdressだと思います。

Diff

1- const Adress = plainbody.match(regTel)[0].replace('住所:',''); 2+ const Adress = plainbody.match(regAdress)[0].replace('住所:','');

それから、エラーになっているのはnew RegExpmatchしていないからだと思います。
お名前:お名前:は違いますので15行目、16行目のnew RegExpの場所を修正する必要があると思います。

投稿2021/09/20 01:44

fake_shibe

総合スコア806

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

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

shz4x4

2021/09/20 02:25

ありがとうございます。 何度も申し訳ありません。 ご指摘いただいた部分を修正しましたが、やはり継続してエラーが出てしまします。
fake_shibe

2021/09/20 02:49

エラーメッセージの内容を教えて頂けたら対処できるかもしれません。 もしかしたら、const plainbody = message.getPlainBody();で取得されているメールの内容に、お名前:、住所:が含まれていない可能性もあります。 console.log(plainbody)かLogger.log(plainbody)でメールの内容を確認した方がいいかもしれません。
shz4x4

2021/09/20 05:01

ありがとうございます。 ログを確認しましたが、メール本文には、お名前:や住所:が含まれておりました。
shz4x4

2021/09/20 05:22

この度はご助力いただき誠にありがとうございました。 fake_shibe様、qnoir様のおかげで解決することができました。 感謝申し上げます。
guest

0

19行目のところでエラーということで、以下のイージーミスだと思います。
**match[0]**とするところを、**replace[0]**になっています。

Diff

1- const Name = plainbody.match(regName).replace[0]('お名前:',''); 2+ const Name = plainbody.match(regName)[0].replace('お名前:','');

投稿2021/09/19 21:30

fake_shibe

総合スコア806

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

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

shz4x4

2021/09/20 00:34

ご回答ありがとうございます。 イージーミス部分を修正しましたが、同様のエラーが継続して発生してしまいます。 他に原因があるのでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問