GASで正規表現を使って
文字列を抽出・置換・検証する方法
正規表現(RegExp・文字列のパターンを表す記法)を使えば、メールやURLの抜き出し、電話番号の整形、入力チェックをGASの標準機能だけで実装できます。match・replace・testを、動くコードで順に解説します。
Table of Contents
GASの正規表現でできること
GASはV8ランタイム上で動くため、通常のJavaScriptと同じ正規表現をそのまま使えます。 ライブラリの追加は不要で、/パターン/というリテラルを書くだけで始められます。用途は大きく3つに分かれます。
抽出(match)
文中からメール・URL・日付など、欲しい部分だけを取り出す
置換(replace)
電話番号の整形や個人情報のマスクなど、パターンに沿って書き換える
検証(test)
郵便番号やメールが決まった形式かどうかを true / false で判定する
セル単位で「検索して置換」したいだけなら、専用のTextFinderの方が高速です。正規表現は「1つのセルの中の文字列を細かく解析・加工したい」ときに真価を発揮します。
matchで文字列を抽出する
String.match()は、パターンに一致した部分を返します。g(グローバル)フラグを付けると、一致したすべての箇所を配列で受け取れます。 一致が0件のときはnullが返るため、|| []で空配列に受けておくとエラーを防げます。
// メールアドレスを1件だけ取り出す
function extractEmail(text) {
const re = /[\w.+-]+@[\w-]+\.[\w.-]+/; // ざっくり形式を表す正規表現
const m = text.match(re);
return m ? m[0] : ""; // 見つからなければ空文字
}
// 文中のURLをすべて配列で取り出す(gフラグ)
function extractAllUrls(text) {
const re = /https?:\/\/[^\s、。]+/g;
return text.match(re) || []; // 一致0件のときは null なので || [] で受ける
}
function demo() {
const body = "問い合わせは info@example.com へ。詳細は https://example.com/faq を参照。";
Logger.log(extractEmail(body)); // info@example.com
Logger.log(extractAllUrls(body)); // [https://example.com/faq]
}replaceで一括置換・整形する
String.replace()にgフラグ付きの正規表現を渡すと、一致したすべての箇所を書き換えられます。 置換後の文字列では$1・$2でキャプチャした部分(()で囲んだ範囲)を再利用できます。電話番号を数字だけにしたり、メールをマスクしたりする定番処理です。
// 電話番号からハイフン・かっこ・空白を取り除いて数字だけにする
function normalizePhone(text) {
return String(text).replace(/[^0-9]/g, "");
}
// メールアドレスの@より前を伏せ字にする(gフラグで文中すべて)
function maskEmail(text) {
// $2 は2つ目の(...)= ドメイン部分をそのまま残す
return String(text).replace(/([\w.+-]+)@([\w.-]+)/g, "***@$2");
}
function demo() {
Logger.log(normalizePhone("03-1234-5678")); // 0312345678
Logger.log(maskEmail("担当 taro@example.com まで")); // 担当 ***@example.com まで
}testで入力を検証する
形式が正しいかどうかを判定したいときはRegExp.test()を使います。true/falseが返るので、フォーム回答やインポートデータのバリデーションに向いています。ポイントは、 先頭の^と末尾の$で「文字列全体が形式に一致すること」を明示することです。これがないと、余計な文字が混じっていても一致してしまいます。
// メールアドレスの形式チェック(^ と $ で全体一致にするのが重要)
function isValidEmail(value) {
const re = /^[\w.+-]+@[\w-]+\.[\w.-]+$/;
return re.test(String(value).trim());
}
// 郵便番号 123-4567 形式かどうか
function isValidPostalCode(value) {
return /^\d{3}-\d{4}$/.test(String(value).trim());
}
function demo() {
Logger.log(isValidEmail("taro@example.com")); // true
Logger.log(isValidEmail("taro@example")); // false(ドメインに . がない)
Logger.log(isValidPostalCode("100-0001")); // true
}キャプチャグループで一部だけ取り出す
()で囲んだ部分(キャプチャグループ)を使うと、一致の中から必要な断片だけを抜き出せます。(?<name>...)の名前付きグループにすると、m.groups.yearのように名前で取り出せて読みやすくなります。すべての一致を1つずつ処理したいときはmatchAll()をfor...ofで回すのが確実です。
// 2026/07/23 や 2026-07-23 から年・月・日を取り出す(名前付きグループ)
function parseDateParts(text) {
const re = /(?<year>\d{4})[\/-](?<month>\d{1,2})[\/-](?<day>\d{1,2})/;
const m = String(text).match(re);
if (!m) return null;
const { year, month, day } = m.groups; // groups から名前で取り出せる
return { year, month, day };
}
// #タグ をすべて取り出す(()内=タグ名だけを集める)
function extractTags(text) {
const re = /#([^\s#]+)/g;
const tags = [];
for (const m of String(text).matchAll(re)) {
tags.push(m[1]); // m[0]は#付き、m[1]が1つ目の(...)の中身
}
return tags;
}
function demo() {
Logger.log(parseDateParts("納期は 2026/07/23 です")); // {year:2026, month:07, day:23}
Logger.log(extractTags("#GAS #正規表現 の話")); // [GAS, 正規表現]
}スプレッドシートの列を一括検証する
実務では、スプレッドシートの1列をまとめてチェックする場面が多くあります。getValues()で列を一括取得し、map()で1行ずつ検証して、結果をsetValues()で一括書き込みします。1セルずつ読み書きするより大幅に速く、実行時間制限にも余裕が生まれます。
// B列(メールアドレス)を一括検証し、C列に「OK / 要確認」を書き込む
function validateEmailColumn() {
const sheet = SpreadsheetApp.getActive().getSheetByName("会員");
const last = sheet.getLastRow();
if (last < 2) return; // ヘッダーだけなら何もしない
const emails = sheet.getRange(2, 2, last - 1, 1).getValues(); // 一括取得
const re = /^[\w.+-]+@[\w-]+\.[\w.-]+$/;
const results = emails.map(([email]) => {
const ok = re.test(String(email).trim());
return [ok ? "OK" : "要確認"];
});
sheet.getRange(2, 3, results.length, 1).setValues(results); // 一括書き込み
}実務での注意点
1. gフラグ付き正規表現の使い回しに注意
gフラグ付きのRegExpオブジェクトはlastIndex(次に探す位置)を内部に保持します。同じオブジェクトでtest()を繰り返すと、位置がずれて結果が交互に変わることがあります。検証用の正規表現にはgフラグを付けないか、ループ内で毎回リテラルを作り直しましょう。
2. 全角文字は \d や \w にマッチしない
「123」のような全角の数字・英字は、半角前提の\dや\wでは拾えません。検証の前に半角へ正規化するか、[0-9]のように全角の範囲を明示します。
3. 入力から動的に正規表現を作るときはエスケープする
利用者が入力したキーワードをそのままnew RegExp()に渡すと、.や*が特殊文字として解釈されてしまいます。次のエスケープ関数を通してから渡すと、記号を「ただの文字」として安全に扱えます。
// 利用者の入力をそのまま検索語に使うときは記号をエスケープする
function escapeRegExp(text) {
return String(text).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function buildSearch(keyword) {
// 例: "a.b" をそのままの文字列として検索する正規表現を作る
const re = new RegExp(escapeRegExp(keyword), "gi");
return re;
}
function demo() {
const re = buildSearch("Ver.1.0");
Logger.log("Ver.1.0".match(re)); // [Ver.1.0](. がワイルドカードにならない)
}まとめ
GASの正規表現は、抽出はmatch、置換はreplace、検証はtestと、目的ごとにメソッドを覚えるだけで実務のほとんどをカバーできます。全体一致には^...$、gフラグのlastIndex、全角対策の3点に気をつければ、フォーム検証やデータクレンジングを安定して自動化できます。
よくある質問
必要ありません。GASのV8ランタイムは標準のJavaScriptと同じ正規表現(RegExp)をそのまま使えます。/パターン/ のリテラルや new RegExp() を書くだけで、match・replace・test などのメソッドが利用できます。matchAll や名前付きキャプチャグループなどの新しい記法も動きます。
1件だけ取り出したいときや、キャプチャグループの中身を細かく見たいときは match が向いています。gフラグを付けて「すべての一致」を配列で受け取りたいときも match([0] だけの配列)で足ります。各一致のキャプチャ内容まで繰り返し処理したいときは matchAll を for...of で回すのが確実です。
\d や \w は半角の数字・英字にしかマッチしないためです。「123」のような全角文字を扱うときは、比較の前に半角へ正規化するか、[0-9] のように全角の範囲を明示的に書きます。実務では正規化関数を1つ用意して、検証前に必ず通すのがおすすめです。
gフラグ付きのRegExpオブジェクトは lastIndex(次に探す位置)を内部に保持するため、同じオブジェクトで test() を繰り返すと一致位置がずれて true と false が交互に出ることがあります。ループの中では毎回リテラルで作り直すか、検証用の正規表現にはgフラグを付けないのが安全です。
そのまま new RegExp(入力値) にすると、入力に含まれる . や * などが特殊文字として解釈され、意図しない一致やエラーの原因になります。記号を \ でエスケープする関数を通してから RegExp に渡してください。本文の「実務での注意点」でエスケープ関数のコードを紹介しています。
GAS開発・業務Webシステムを
相談する。
文字列の抽出・検証以外にも、フォーム連携・帳票出力・データクレンジングなど、日々の業務を自動化するGAS開発をご相談いただけます。