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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Google Apps Script

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

JavaScript

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

正規表現

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

Google

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

Q&A

解決済

2回答

5185閲覧

[Google apps script]配列内を正規表現で検索してインデックス番号を取得したい。

jinyo

総合スコア59

Google Apps Script

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

JavaScript

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

正規表現

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

Google

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

0グッド

2クリップ

投稿2019/01/08 16:18

編集2019/01/09 03:04

お世話になります。
Google apps scriptを勉強を始めたばかりのものです。(Javascriptは触ったことがありません)

<質問>
GASにて配列内を正規表現で検索してTrueの場合に該当インデックス番号を返してくれる関数などはありませんでしょうか?
(indexOfの引数に正規表現を渡すようなイメージです。)

自分が考えたのは、配列.lengthの数でループしながら、Serachかmatchで検索してヒットしたらイテレータの番号を控える、というものですが、もっと簡単にできる関数はないのかなと探しておりますが見つけることができませんでした。

良い案をご存知の方がいらっしゃいましたらご教示のほど、宜しくお願いいたします。

補足追記
インデックスがなぜ必要かという点に関しまして、説明不足で申し訳ありません。以下に補足させて頂きます。
検索したい当該の配列というのはメールで複数の取引先から送られてくる商品データのスプレッドシートを解析する為に各シートのdatarangeが入ります。配列内の商品コード列を検索して該当する商品名を取得したいとします。(要はEXCELのvlookupです。)シートは取引先によりフォーマットを改造している方がいるので、商品コード列が何列目にあるのかシートによりバラバラです。さらに最悪なことに列見出し項目名も「商品コード」だったり「品目コード」、「コード」だったりします。取引先によって処理を分けることも考えましたが、同じ取引先でも今後フォーマットが変わる可能性があります。

vlookupするにあたり、どの列が商品コード列なのか、を、曖昧検索で判定したく思いまして今回の質問に至った次第です。
(フォーマットを統一しろ!という話ですが、他社が絡む話なので強制しにくかったりいろいろありまして時間がかかりそうでして。。。(涙))

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

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

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

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

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

guest

回答2

0

ベストアンサー

他の方法もあると参考になるかもしれないと思いましたので、いくつかある方法の一つとして、test()reduce()を使用する方法について記載させていただきます。この方法でも配列をループして結果を取得する流れです。

サンプルスクリプト

javascript

1var ar = ["foo", "bar", "baz"]; // サンプル配列 2var regex = /b/; // ここに正規表現を設定 3var res = ar.reduce(function(ar, e, i) { 4 if (regex.test(e)) ar.push(i); 5 return ar; 6}, []); 7Logger.log(res) // [1, 2]
  • test()は、与えた文字列が正規表現にマッチするとtrue、マッチしないとfalseを返します。
  • reduce()では、test()がtrueを返す場合に配列のインデックスを取得しています。

最終的にマッチしたインデックス[1, 2]が配列として返されます。

参考

投稿2019/01/09 02:03

kisojin

総合スコア899

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

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

jinyo

2019/01/09 14:41

kisojinさま ご意見ありがとうございます。一人目の回答者様のサンプルコードにもあったのですが、自分はコールバック関数というのを本日初めて知りまして、いまだ理解できずにいます・・・。kisojinさまのサンプルコードをステップインしてみてループ処理してるのはわかりましたが、わからないのは文法です。「function(ar, e, i)」の第2・第3引数のe,iはなんなのでしょうか? ・・・話が脱線してすいません。もう少し文法の基本とコールバック関数について学びたいと思います。
kisojin

2019/01/10 00:45 編集

jinyo様: ご返事頂き有難うございます。サンプルではプロセスコスト(https://gist.github.com/tanaikech/848aeafaac1ec676900bb78e3ce220b6)を考慮した結果、forループではなくreduceを提案させていただきました。例えばサンプルにあるreduceで行われている内容をforループを使って表現すると下記のようになります。これとサンプルを比較することで動作の理解に繋がりますと幸いです。 var ar = ["foo", "bar", "baz"]; // サンプル配列 var regex = /b/; // ここに正規表現を設定 var res = []; for (var i = 0; i < ar.length; i++) { if (regex.test(ar[i])) res.push(i); } 余談ですが、GASはJavaScript 1.7を使用していますので内包表記として下記のように書くことも可能です。ただし、将来のアップデートのことを考えると、あまりお勧めできません。 var ar = ["foo", "bar", "baz"]; // サンプル配列 var regex = /b/; // ここに正規表現を設定 var res = [i for (i in ar) if (regex.test(ar[i]))]; papinianus様: サポート有難うございます。
papinianus

2019/01/10 02:49

質問者ではないですが、大変参考になる記事をありがとうございました。 forのほうが遅い(有意に遅くなり得る)とは思いませんでした。測定せよ、ですね。
kisojin

2019/01/10 03:12

papinianus様: コメントありがとうございます。GASは他の言語とは違ったコストを示すようで、このような測定結果を見ると、どの方法を使用するとよさそうかの判断材料に使うことができます。他にもいろいろな測定結果があり、こちら( https://github.com/tanaikech/taking-advantage-of-google-apps-script#benchmarks )でご覧いただけます。仰る通り、測定の重要性が分かります。
jinyo

2019/01/10 15:43

kisojin様、papinianus様 ご提示いただいたURLをもとにサンプルで動作確認をして一応動作は理解しました。varで変数定義も代入もしていないのにfunction()に勝手に値(ar, e, i)が渡されていることにいまだに腑に落ちないというか、引っ掛かる部分がありますが、とりあえず、こういうものだとスルーして、なんとかコードに落とし込み問題は解決しました。お二人のおかげです。ありがとうございます。WEBページの情報ですと、コールバック関数=メンテナンス性・非同期処理・・なんていう記事が多いようでしたが、速度にも違いがでるのですねー!頭に入れておきます。
kisojin

2019/01/12 05:25

jinyo様: macaron_xxx様のコメントにもあるようにポリフィルを見るとその流れを確認しやすいかと思います。また、例えば、最初はコストよりも理解度を優先してfor loopを使用し、その後、コスト優先に切り替える方法もあるかと思います。流れが分かっていると、ループの部分を変更することで理解しやすくなるのではないかと思いました。コストの件ですが、昨年末にGASへのV8エンジン搭載の話も出ていましたので、今後のGASのアップデートでfor loopのコストは改善されるものと推測しています。 macaron_xxx様: サポート有難うございます。
guest

0

やりたいことは、MDN / Array.prototype.findIndex()だと思いますが、残念ながらGoogle App ScriptのArray.prototypeにはないです。

こういうときは、MDNの互換コードの項が役に立つのですが、そこを見ると質問者様のおっしゃる

自分が考えたのは、配列.lengthの数でループしながら、Serachかmatchで検索してヒットしたらイテレータの番号を控える、というもの

そのものが実装例として示されていますので、その方法で妥当だと思います。

--
蛇足ですが良い案も、とのことなので、必ずしも良くはないですが別の案としては、map()で、indexとvalueのペアにしてから、filter()でvalue側に対して、matchを使って、得た結果のindex側を取るとかも考えられます。

javascript

1["ab","bc"].map(function(e,i,a){return [i,e];}).filter(function(e,i,a){ return e[1].match(/b./)})[0][0];

個人的には「indexが本当に必要なのか」という点で、前提となるやりたいことを補足した質問であれば、もっと簡潔な回答もできるのではないかと思いました。

投稿2019/01/09 01:04

papinianus

総合スコア12705

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

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

jinyo

2019/01/09 14:15

papinianusさま ご意見ありがとうございます。私の考えた方法が妥当だ、と仰っていただいたことで、つまづきかけたところに大変嬉しいお言葉で少しばかり自信が付いたかと思ったのですが、ご提案いただいたmap関数、Filter関数の中にでてくるFunctionとは何ぞや、と思って調べてみて、VBAしか知らない自分には、初めて目の当たりにするコールバック関数というものに何だかすごそうと感動しつつ、今日のところは理解できる気がしないので、もう少し時間をかけて試してみます。 また、「indexが本当に必要なのか」というご意見につきましては、私の説明不足の点もありましたので補足を追記いたしました。もし、お時間あるようでしたらご確認・ご意見いただければ幸いでございます。
papinianus

2019/01/10 00:14

インデクスが必要な事情を理解しました。この背景だと確かに必要そうですね。浅慮についてお詫びします。 コールバックは無理してあるいは焦って覚える必要はないというのはそのとおりだと思います。必ずしも効率がよいわけでもないです。必要に迫られてからで充分でしょう
jinyo

2019/01/10 15:55

浅慮だなどととんでもございません。最初の質問内容だけでは、もう少し簡単な別のアプローチからの解決方法をご提示いただける可能性も含んでいましたからね。 今日はreduceについて理解しました(ざっくりと・・)。こちらのmapとfilterはコールバックがワンステートメントに2つも入ってるので気後れしますね・・・ww。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問