シートを目視で探すのをやめたい
日常業務において、Googleスプレッドシート内から特定の文字列やキーワードを検索し、そのセル位置を特定する作業は頻繁に発生します。データ量が少ない場合は手動での目視チェックや検索機能で対応できますが、数千行を超えるデータや日次で更新されるデータを扱う場合、手作業によるミスや大幅なタイムロスが避けられません。
そこで活躍するのが、Google Apps Script (GAS) の自動化技術です。GASを用いてシート内のテキスト検索を自動化すれば、特定の文字列が含まれるセルの抽出、背景色のハイライト、さらにはデータの一括置換までを一瞬で完了させることが可能になります。基本の検索と、部分一致で隣まで拾う点を書きます。
該当セルの番地を取る
まずは、スプレッドシート内から特定のキーワードを検索し、該当するセルの位置(セル番地)を取得するための次のコードです。以下のコードを使用するだけで、シート全体のテキスト検索が完結します。
const sheet = SpreadsheetApp.getActiveSheet();
const textFinder = sheet.createTextFinder("検索文字");
const results = textFinder.findAll();
results.forEach(cell => Logger.log(cell.getA1Notation()));
上の4行がやっていること
上のコードを1行ずつ見ます。
- 1行目:
const sheet = SpreadsheetApp.getActiveSheet();
現在アクティブになっている(開いて操作している対象の)スプレッドシートのシートオブジェクトを取得し、定数sheetに格納しています。特定のシート名を明示的に指定して操作したい場合は、getSheetByName("シート名")に置き換えることで、バックグラウンドでの安定した処理が可能になります。 - 2行目:
const textFinder = sheet.createTextFinder("検索文字");
この検索処理の核となるTextFinderオブジェクトを生成しています。引数には検索したい文字列(ここでは「検索文字」)を指定します。この段階ではまだ検索自体は実行されておらず、「何をどこから検索するのか」という条件を定義した準備状態となります。 - 3行目:
const results = textFinder.findAll();
定義したTextFinderの条件に基づき、実際にシート全体を検索します。findAll()メソッドは、条件に一致したすべてのセルをGASのRangeオブジェクトの配列として返し、定数resultsに格納します。一つだけ見つけたい場合はfindNext()を使用することも可能です。 - 4行目:
results.forEach(cell => Logger.log(cell.getA1Notation()));
取得したセルの配列resultsに対して、forEachメソッドを用いてループ処理を行います。各セル(cell)に対してgetA1Notation()を実行することで、「A1」や「C5」といった人間が認識しやすいA1記法(セル番地)の文字列を取得し、実行ログに出力しています。
配列を回すより速い理由
スプレッドシート内のデータを検索する際、GASの初期段階では「getDataRange().getValues()でシート全体のデータを二次元配列として取得し、for文などの配列ループを使って1行ずつ値を判定する」という実装手法がよく紹介されていました。しかし、この手法には実務上クリアすべき課題がありました。
6分制限に当たりにくい
TextFinderを活用する最大の強みは、配列ループを使わずにシート全体の文字列を高速検索できる点にあります。配列を使った自前のループ処理では、データ量が数万行に及ぶと処理時間が極端に長くなり、GASの実行時間上限(6分ルール)に抵触するタイムアウトの危険性が高まります。
一方、TextFinderはGoogleのサーバー側で最適化された検索アルゴリズムを呼び出しています。そのため、自前で二次元配列をループさせるよりも圧倒的に処理速度が速く、かつ記述するコード量も数行に収まるため、可読性とメンテナンス性が上がる。
年号や電話番号みたいな型で探す
実務でのデータ処理においては、「完全一致の単語」だけでなく、「特定のパターンを満たす文字列」を検索したいシーンが多々存在します。例えば、「090から始まる電話番号」や「特定のドメインを持つメールアドレス」、「エラーを示す不規則なログ文字列」などです。
useRegularExpression(true) による正規表現対応
TextFinderは、正規表現(Regular Expression)による柔軟な検索にも標準仕様として対応しています。正規表現を有効にするためには、createTextFinder()の後にuseRegularExpression(true)をチェーン(連結)して指定します。
const sheet = SpreadsheetApp.getActiveSheet();
// 「2023年」や「2024年」などの4桁の年数表記を正規表現で一括検索する例
const textFinder = sheet.createTextFinder("[0-9]{4}年").useRegularExpression(true);
const results = textFinder.findAll();
results.forEach(cell => Logger.log(cell.getValue()));
この仕様を活用することで、表記揺れがある生データの中から目的のセルだけを正確に抽出するといった、実務に直結する高度なデータクレンジング作業が非常に簡単に実装できます。
見つかったあと、何をするか
検索してセルの位置を特定した後、その情報を使って何ができるのか。見つかったあとによくやるのは次の2つです。
1. 該当セルの背景色を一括変更してハイライトする
検索して見つかったセルを視覚的に目立たせたい場合、取得したRangeオブジェクトに対して装飾メソッドを呼び出すだけで実現できます。例えば、特定のNGワードが含まれるセルを自動で黄色に塗りつぶす確認ツールなどが作れます。
// 検索結果のすべてのセルの背景色を黄色に変更
results.forEach(cell => cell.setBackground('#ffff00'));
2. 該当するテキストを別の値に一括置換する
単に検索するだけでなく、古い部署名や商品名を一括で新しい名称に変更したい場合は、replaceAllWith()メソッドを使うことで一瞬で置換処理が完了します。
// 「旧部署名」を「新部署名」に一括置換
sheet.createTextFinder("旧部署名").replaceAllWith("新部署名");
Pineapple までヒットする件
TextFinderは非常に便利ですが、デフォルトの仕様を正確に理解していないと、意図しない検索結果になる「落とし穴」が存在します。実務でバグを生み出さないための注意点を解説します。
大文字小文字の区別と完全一致の制御
TextFinderのデフォルト設定では、アルファベットの大文字と小文字を区別せず、さらに「部分一致」で検索が行われます。そのため、「Apple」を検索したつもりが、意図せず「Pineapple」のセルまでヒットしてしまうといった挙動が発生します。これを防ぐためには、検索条件を厳密に指定するメソッドを追加で付与します。
| 追加するメソッド | 仕様 |
|---|---|
matchCase(true) |
大文字と小文字を厳密に区別して検索します(Aとaを別物とする)。 |
matchEntireCell(true) |
セル内の文字列が検索文字列と「完全に一致する」場合のみヒットさせます(部分一致の排除)。 |
// 大文字小文字を区別し、セル内容と完全一致するものだけを厳密に検索するコード例
const finder = sheet.createTextFinder("Apple").matchCase(true).matchEntireCell(true);
const results = finder.findAll();
部分一致のままだと隣まで拾う
Google Apps Scriptを用いたスプレッドシート内のテキスト検索において、TextFinderクラスは実務でよく使う機能です。従来の二次元配列を用いたループ処理の欠点を克服し、処理速度と短い記述量でシート全体の検索を完了させることができます。
本記事で紹介した基本の実装コードから始まり、useRegularExpression(true)を用いた正規表現による高度なパターン検索、そして実務で陥りがちな部分一致検索の落とし穴への対策までを理解しておけば、スプレッドシートのデータ抽出・操作で困ることはなくなるはずです。ぜひ日々のデータ集計や業務自動化のプログラムに取り入れ、部分一致の指定だけ先に決めておく。

