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

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

ただいまの
回答率

87.59%

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 2,962

score 34

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

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

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

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+4

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

サンプルスクリプト

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

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

参考

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/11 00:43

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

    キャンセル

  • 2019/01/11 13:19 編集

    >varで変数定義も代入もしていないのにfunction()に勝手に値(ar, e, i)が渡されていることにいまだに腑に落ちない
    reduceのポリフィルをみていただくと、ちゃんとar, e, iが渡されていることがわかりますよ。
    https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Polyfill

    キャンセル

  • 2019/01/12 14:25

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

    macaron_xxx様:
    サポート有難うございます。

    キャンセル

+3

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

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

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

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

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

["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 23:15

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

    キャンセル

  • 2019/01/10 09:14

    インデクスが必要な事情を理解しました。この背景だと確かに必要そうですね。浅慮についてお詫びします。

    コールバックは無理してあるいは焦って覚える必要はないというのはそのとおりだと思います。必ずしも効率がよいわけでもないです。必要に迫られてからで充分でしょう

    キャンセル

  • 2019/01/11 00:55

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

    キャンセル

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

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る