【データクレンジング】Googleスプレッドシートで住所データの表記揺れを自動解消!(そのまま使える無料テンプレート配布)

住所データクレンジング記事のアイキャッチ画像 自動化事例

顧客リストや送付先リストを管理していると、こんなお悩みはありませんか?

  • 「DM(ダイレクトメール)を送りたいのに、住所がバラバラで名寄せが大変…」
  • 「システムにデータを取り込みたいのに、エラーが出てしまう」
  • 「”1-1-1″と”一丁目1番1号”が混在していて、手作業での修正に時間がかかっている」

こうした「住所の表記揺れ」は、データの正確性を損ない、業務効率を大きく低下させる原因となります。

この記事では、Googleスプレッドシートと、Google Apps Script(GAS)という仕組みを活用し、これらの住所表記揺れを「ボタン一つで」自動的に修正する方法を、そのまま使えるサンプルシート付きでご紹介します。

無料配布:住所表記揺れ修正テンプレート

全角・半角の統一や、「1-1-1」→「一丁目1番1号」への変換などをボタン一つで実行できるテンプレートを無料で配布しています。
プログラムを書く必要はなく、コピーしてすぐに利用可能です。

【テンプレートで自動化できること】

  • 英数字・スペース・記号の全角/半角統一
  • 「1-1-1」等の省略表記を「一丁目1番1号」へ正規化
  • 「札幌市…」など都道府県が抜けているデータの補完
  • 漢数字(丁目)と算用数字(番地)の使い分けルール適用

普段の手作業による名寄せやクレンジング負荷を大幅に削減できます。
以下のフォームから、今すぐテンプレートをお受け取りください。

    法人名(必須)

    氏名(必須)

    メールアドレス(必須)

    電話番号(必須)

    そもそもGAS (Google Apps Script) とは?

    GAS(ガス)は、Googleが提供している、ちょっとしたプログラム(スクリプト)を作れる環境のことです。Excelの「マクロ」を使ったことがある方は、それに近いイメージを持っていただくと分かりやすいかもしれません。

    スプレッドシートやGmail、Googleカレンダーなどを自動で操作でき、無料で利用できます。

    今回は、このGASを使って「A列に入力された住所を、ルールに従ってクレンジングし、B列に出力する」という自動処理を行います。プログラミングの事前学習は不要ですので、ぜひお試しください。
    GASについて、さらに詳しく知りたい方はこちらの記事をご覧ください。

    表記揺れが放置されると、データ突合の不整合や業務システムのエラー発生など、運用上のリスクが高まります。自動化により、従来の手作業による修正作業の負荷を大幅に軽減し、人的ミスを防止するだけでなく、業務効率の向上にもつなげましょう。

    このツールでできること(表記揺れ修正のルール)

    今回ご紹介するスプレッドシートでは、以下のルールに基づいて住所データのクレンジングを行います。

    (1)対応可能な表記揺れパターン

    以下のような、よくある表記揺れに対応しています。

    • 「丁目、番、号」の表記が統一されていない。
      • 例:「1-1-1」「1-1-1(全角ハイフン)」「1丁目1-1」「1丁目1番1号」「一丁目一番一号」「1の1の1」など
    • 英数字が全角と半角で統一されていない。
    • 不要なスペースや記号(カンマ、スラッシュ、括弧など)が混入している。
    • 都道府県が抜けている。
      • 例:「札幌市〇〇….」「横浜市〇〇….」「名古屋市〇〇….」

    (2)修正後の統一ルール

    上記の表記揺れを、日本国内の住所データ表記として一般的な、以下のルールに沿って修正します。

    • 「丁目、番、号」の表記を統一します。
      • 「丁目」は漢数字(例:一丁目、十丁目)
      • 「番」「号」はアラビア数字の半角(例:1番2号)
    • 英数字はすべて半角で統一します。
    • 不要なスペースや記号(カンマ、スラッシュ、括弧など)は削除します。
    • 都道府県名が抜けている場合に補完します。
      • 例:「札幌市〇〇….」→「北海道札幌市〇〇….」

    注意点

    本ツールは、上記のルールに基づいた一般的な表記揺れの修正を目的としています。そのため、非常に特殊な表記(例:旧漢字の地名、〇〇方などの表記)や、建物名の中に数字が含まれる場合など、全ての住所パターンで完璧な変換を保証するものではありません。実行結果は必ず目視でもご確認いただくようお願いいたします。

    【画像で解説】サンプルスプレッドシートの使い方

    早速、使い方を見ていきましょう。ステップはたったの3つです。

    Step1:事前準備

    1.テンプレートの用意

    ページ上部のフォームからダウンロードした「住所変換スプレッドシート」を開き、ご自身のGoogleドライブに「コピーを作成」してください。
    ※このシートには、GASのプログラムコードと市区町村マスタがあらかじめ設定されています。

    2.対象データの用意

    表記揺れを修正したい実際の住所データ(ExcelまたはCSV形式)をご用意ください。

    補足

    コピーしたスプレッドシートには、「住所変換」シートの他に、都道府県の補完に使用する「市区町村マスタ」シートが含まれています。このシートのデータをもとに、都道府県名が抜けている住所を補完します。

    Step2:対象データの更新

    コピーしたスプレッドシートの「住所変換」シートを開き、A列の3行目以降(A3セル)に、クレンジングしたい住所データを貼り付けます。

    住所の対象データを更新

    Step3:住所変換の実行

    1.Google Apps Script(GAS)の実行許可(初回のみ)

    シートの上部(または画像内)にある「住所変換開始」という図形ボタンをクリックします。
    初めて実行する際は、スクリプトの実行許可を求めるポップアップが表示されます。
    詳しい承認手順については、こちらの解説記事をご覧ください。

    住所データクレンジング記事の変換開始

    2.変換の実行

    許可後に実行すると、A列の住所データが自動で修正され、B列に出力されます。

    住所データクレンジング記事の変換完了

    (興味がある方向け)スクリプトの簡単な解説

    「ボタン一つで便利だけど、裏側では何が動いているの?」と気になる方のために、GASコード(プログラム)の中身を簡単に解説します。

    コード全体は以下のようになっています。

    /**********************************************
     * (1) 住所データ変換メイン処理
     *     (1-1) 「住所変換」シートのB3セル以降をクリア
     *     (1-2) A3セル以降の住所データを取得
     *     (1-3) 取得した住所を正規化・変換
     *     (1-4) 変換結果をB3セル以降に書き込む
     **********************************************/
    function ConvertAddresses() {
      // (1-1) 「住所変換」シートのB3セル以降をクリア
      const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
      const address_sheet = spreadsheet.getSheetByName("住所変換");
      address_sheet.getRange("B3:B").clearContent();
    
      // (1-2) A3セル以降の住所データを取得
      const last_row = address_sheet.getLastRow();
      if (last_row < 3) {
        return; // 住所データが無い場合は終了
      }
      const address_range = address_sheet.getRange(`A3:A${last_row}`);
      const address_data = address_range.getValues();
    
      // (1-3) 取得した住所を正規化・変換し、配列形式にまとめる
      const formatted_addresses = address_data.map(row => {
        const original_address = String(row[0]).trim();
    
        if (!original_address) {
          return [""];
        }
        // 住所を正規化・フォーマット変換する子関数呼び出し
        const formatted_address = processAddress(original_address);
        return [formatted_address];
      });
    
      // (1-4) 変換結果をB3セル以降に書き込む
      address_sheet.getRange(3, 2, formatted_addresses.length, 1).setValues(formatted_addresses);
    }
    
    /****************************************************************
     * (2) 住所の正規化とフォーマット変換を行う子関数
     *     (2-1) 入力住所を半角変換・不要文字除去で都道府県の有無を判定
     *     (2-2) 英数字を半角統一し、不要なスペースや記号を削除
     *     (2-3) 「〇の〇の〇」「〇-〇-〇」を「丁目番地号」形式へ変換
     *     (2-4) 「〇丁目」は漢数字に、「〇番」「〇号」は半角数字に変換
     *     (2-5) 漢数字の「番」「号」を半角数字へ変換
     *     (2-6) 都道府県未特定の場合、市区町村マスタから推定
     *     (2-7) 推定都道府県が特定できたら先頭に付与し、重複部分を除去
     ****************************************************************/
    function processAddress(input_str) {
      // (2-1) 入力住所を半角変換&不要文字除去したnorm_addressで都道府県名の有無を判定
      const original_address = String(input_str).trim();
    
      let norm_address = convertToHalfWidth(original_address)
        .replace(/[\s ,、\/()()[\]「」「」【】・・『』"_]/g, "");
    
      const pref_regex = /^(東京都|北海道|(?:京都|大阪)府|[一-龥]{2,4}県)/;
      let inferred_pref = "";
      let pref_match = norm_address.match(pref_regex);
      if (pref_match) {
        inferred_pref = pref_match[0];
      }
    
      // (2-2) 英数字を半角統一し、不要なスペースや記号を削除
      let address_str = convertToHalfWidth(original_address);
      address_str = address_str.replace(/[\s ,、\/()()[\]「」「」【】・・『』"_]/g, "");
    
      // (2-3) 「〇の〇の〇」「〇-〇-〇」「〇丁目〇-〇」を「〇丁目〇番〇号」形式に変換
      address_str = address_str
        .replace(/(\D+?)(\d+)の(\d+)の(\d+)/, "$1$2丁目$3番$4号")
        .replace(/(\D+?)(\d+)[\--](\d+)[\--](\d+)/, "$1$2丁目$3番$4号")
        .replace(/(\d+)丁目(\d+)[\--](\d+)/g, "$1丁目$2番$3号");
    
      // (2-4) 「〇丁目」は数字を漢数字に、「〇番」「〇号」は数字を半角に変換
      address_str = address_str.replace(/(\d+)丁目/g, function(_, num) {
        const kanji_num = convertNumberToKanji(parseInt(num, 10));
        return kanji_num + "丁目";
      });
      address_str = address_str.replace(/(\d+)番/g, function(_, num) {
        const half_num = convertDigitsToHalfWidth(num);
        return half_num + "番";
      });
      address_str = address_str.replace(/(\d+)号/g, function(_, num) {
        const half_num = convertDigitsToHalfWidth(num);
        return half_num + "号";
      });
    
      //(2-5) 漢数字の「番」「号」を半角数字へ変換
      address_str = address_str.replace(/([一二三四五六七八九十百千]+)番/g, function(_, kanji_num) {
        const numeric_val = convertKanjiToNumber(kanji_num);
        const half_val = convertDigitsToHalfWidth(String(numeric_val));
        return half_val + "番";
      });
    
      address_str = address_str.replace(/([一二三四五六七八九十百千]+)号/g, function(_, kanji_num) {
        const numeric_val = convertKanjiToNumber(kanji_num);
        const half_val = convertDigitsToHalfWidth(String(numeric_val));
      return half_val + "号";
      });
    
      // (2-6) 都道府県が未特定の場合は市区町村マスタから推定
      if (!inferred_pref) {
    
        const chome_index = address_str.indexOf("丁目");
        const left_part = chome_index >= 0 ? address_str.substring(0, chome_index) : address_str;
    
        const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
        const master_sheet = spreadsheet.getSheetByName("市区町村マスタ");
        const master_data = master_sheet.getDataRange().getValues();
        const unique_municipalities = master_data.reduce((acc, row) => {
        const prefecture   = row[0]; // row[0] → 都道府県名
        const municipality = row[1]; // row[1] → 市区町村名
        if (municipality && !acc[municipality]) {
          acc[municipality] = prefecture;
        }
        return acc;
        }, {});
    
        // left_part に含まれる市区町村名を抽出し、都道府県と対で管理
        const matches = Object.keys(unique_municipalities)
          .filter(municipality => left_part.includes(municipality))
          .map(municipality => ({
            pref: unique_municipalities[municipality],
            mun : municipality
          }));
    
        // {市区町村名: 都道府県名} の形でまとめ直す
        const unique = matches.reduce((acc, item) => {
          acc[item.mun] = item.pref;
          return acc;
        }, {});
        const municipality_names = Object.keys(unique);
    
    
        // municipality_names配列の長さが1件かどうかで判定
         if (municipality_names.length === 1) {
          const municipality = municipality_names[0];
          const prefecture = unique[municipality];
          const city_index = address_str.indexOf(municipality);
          if (city_index >= 0) {
            address_str = address_str.substring(city_index + municipality.length);
          }
          inferred_pref = prefecture + municipality;
        }
      }
    
      // (2-7) 推定都道府県が特定できたら先頭に付与し、重複部を除去
      if (inferred_pref) {
        address_str = address_str.replace(new RegExp('^' + inferred_pref), "");
        address_str = inferred_pref + address_str;
      }
    
      return address_str;
    }
    
    /*******************************************************************
     * (3) 市区名などから都道府県を推定する簡易的な子関数
     *     - 一意に特定できた場合のみ都道府県名を返却
     *******************************************************************/
    function inferPrefecture(address_str) {
      const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
      const master_sheet = spreadsheet.getSheetByName("市区町村マスタ");
      const master_data = master_sheet.getDataRange().getValues();
    
      // 住所内に含まれる市区町村名を検索し、都道府県を配列化
      const matched_prefs = master_data
        .filter(row => address_str.includes(row[1])) // 市区町村名の一致チェック
        .map(row => row[0]); // 該当する都道府県のみを抜き出す
    
      // ユニーク化
      const unique_prefs = [...new Set(matched_prefs)];
    
      // 一意に特定できた場合のみ返却
      if (unique_prefs.length === 1) {
        return unique_prefs[0];
      }
      // 複数または未特定の場合は空文字
      return "";
    }
    
    /****************************************************************
     * (4) 数字を漢数字へ変換(簡易対応)
     *     - 0は「零」、1桁ごとに「十」「百」「千」を適用
     *     - 千以上の数値はそのまま前段に連結
     ****************************************************************/
    function convertNumberToKanji(num) {
      // 数値でない or 負数の場合は空文字
      if (isNaN(num) || num < 0) return "";
      // 0 → 「零」
      if (num === 0) return "零";
    
      const kanji_digits = ["", "十", "百", "千"];
      const kanji_nums = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
    
      let result_str = "";
      let current = num;
      let index = 0;
    
      // 下位桁から順に漢数字を適用
      while (current > 0 && index < kanji_digits.length) {
        const digit = current % 10;
        if (digit !== 0) {
          // 「一十」を「十」として表現する例外ケース
          if (digit === 1 && index === 1) {
            result_str = kanji_digits[index] + result_str;
          } else {
            result_str = kanji_nums[digit] + kanji_digits[index] + result_str;
          }
        }
        current = Math.floor(current / 10);
        index++;
      }
    
      // 千以上の場合、数字をそのまま連結(例:1111 → 1111千百十一)
      if (current > 0) {
        result_str = String(num) + result_str;
      }
      return result_str;
    }
    
    /***********************************************************************
     * (5) 全角英数字を半角英数字に変換する子関数
     ***********************************************************************/
    function convertToHalfWidth(str) {
      return str.replace(/[A-Za-z0-9]/g, function(c) {
        // 全角英数字のUnicodeを-0xFEE0して半角に変換
        return String.fromCharCode(c.charCodeAt(0) - 0xFEE0);
      });
    }
    
    /**********************************************************************
     * (6) 全角数字を半角数字に変換する子関数
     ***********************************************************************/
    function convertDigitsToHalfWidth(num_str) {
      return num_str.replace(/[0-9]/g, function(c) {
        // 全角数字のUnicodeを-0xFEE0して半角に変換
        return String.fromCharCode(c.charCodeAt(0) - 0xFEE0);
      });
    }
    
    /***********************************************************************
     * (7) 漢数字を数値へ変換(簡易対応)
     ***********************************************************************/
    function convertKanjiToNumber(kanji_str) {
      const kanji_map = {
        "零": 0, "一": 1, "二": 2, "三": 3, "四": 4,
        "五": 5, "六": 6, "七": 7, "八": 8, "九": 9
      };
      let result_num = 0;
      let temp_num = 0;
    
      for (let i = 0; i < kanji_str.length; i++) {
        const c = kanji_str[i];
        if (kanji_map[c] !== undefined) {
          // 漢数字(0~9)の場合
          temp_num = temp_num * 10 + kanji_map[c];
        }else if (c === "十") {
          if (temp_num === 0) {
            temp_num = 1;
          }
            temp_num *= 10;
          } else if (c === "百") {
            if (temp_num === 0) {
              temp_num = 1;
            }
              temp_num *= 100;
            } else if (c === "千") {
              if (temp_num === 0) {
                temp_num = 1;
              }
                temp_num *= 1000;
            }
      }
      result_num += temp_num;
      return result_num;
    }

    この自動化処理は、大きく分けていくつかの「関数」(特定の処理を行う命令のまとまり)で構成されています。

    1. ConvertAddresses 関数:全体の「司令塔」

    「住所変換開始」ボタンが押されたときに、最初に動くメインの関数です。

    • (1-1) まず、B列(前回の結果)をクリアします。
    • (1-2) A列に貼り付けられた住所データを読み込みます。
    • (1-3) 読み込んだ住所データを、後述する processAddress 関数に一つずつ渡して、クレンジングしてもらいます。
    • (1-4) クレンジングした住所データをB列に書き込みます。

    2. processAddress 関数:住所を磨き上げる「実行部隊」

    ConvertAddresses 関数から住所データを1件ずつ受け取り、実際にクレンジング(正規化、とも言います)を行う、最も重要な関数です。

    • (2-1) まず、都道府県名が入っているかどうかをチェックします。
    • (2-2) 全角の英数字を半角に変換し、不要なスペースや記号を削除します。
    • (2-3) 「1-1-1」や「1の1の1」といった表記を、「1丁目1番1号」という形式に変換します。
    • (2-4) 「1丁目」を「一丁目」のように漢数字に変換します。
    • (2-5) 「一番」「一号」のように漢数字になっている場合は、半角の「1番」「1号」に変換します。
    • (2-6) もし(2-1)で都道府県名がなかった場合、「市区町村マスタ」シートを参照し、市区町村名(例:「札幌市」)から都道府県名(例:「北海道」)を推定します。
    • (2-7) 推定できた都道府県名を先頭にくっつけて、住所を完成させます。

    3. その他の関数:「補助部隊」

    その他にも、以下のような細かい作業を担当する関数たちが、processAddress 関数をサポートしています。

    • convertToHalfWidth / convertDigitsToHalfWidth:全角の英数字を半角に変換します。
    • convertNumberToKanji:数字(例:10)を漢数字(例:十)に変換します(丁目用)。
    • convertKanjiToNumber:漢数字(例:百)を数字(例:100)に変換します(番・号用)。

    これらの関数が連携することで、手作業では時間のかかる表記揺れの修正を自動で行っています。

    まとめ

    住所の表記揺れは、手動で修正しようとすると非常に手間がかかります。
    本記事でご紹介したスプレッドシートとGASを用いた自動修正手法を活用することで、効率的かつ正確なデータクレンジングが実現できます。
    「そのまま使える」サンプルを、まずはご自身のデータで試してみてください。

    解説は以上です。
    コードの記述やマスタ準備を省略したい方は、以下の配布テンプレートをご利用ください。
    ▶︎ ページ上部のフォームからテンプレートを受け取る(無料)

    この記事の方法で解決できないケースが発生した場合や、さらに高度なデータクレンジングをご希望の場合は、【お問い合わせフォーム】からお気軽にご連絡ください。別途、最適な解決策をご提案いたします。

    ※Googleサービスは、Google LLC の商標であり、この記事はGoogleによって承認されたり、Google と提携したりするものではありません。