JavaScriptで郵便局のutf_ken_all.csvから郵便番号の住所変換を実装する方法

郵便番号を入力して住所変換

Webサイトで住所を入力する際に郵便番号を検索して住所に変換する機能が実装されていることがよくあります。

例えば「1710021」を入力すると「東京都豊島区西池袋」が表示されます。

郵便番号だけで住所の大半が自動入力されるので、現在の住所の入力フォームには実装が必須になっています。

郵便局のutf_ken_all.csvのデータで住所変換

utf_ken_all.csvとは日本郵便が提供する全国の郵便番号データが格納されたCSVファイルです。

このファイルには、全国の都道府県・市区町村・町域レベルの郵便番号情報が含まれています。

utf_ken_all.csvをダウンロードするには郵便番号データダウンロードのWebページにアクセスして、「最新データのダウンロード」のリンクをクリックするか、以下のURLにアクセスすればダウンロードできます。

https://www.post.japanpost.jp/zipcode/dl/utf/zip/utf_ken_all.zip

utf_ken_all.zipを解凍するとutf_ken_all.csvが表示されます。

utf_ken_all.csvの中には郵便番号や住所などのデータが以下のように入っています。

01101,"060  ","0600000","ホッカイドウ","サッポロシチュウオウク","イカニケイサイガナイバアイ","北海道","札幌市中央区","以下に掲載がない場合",0,0,0,0,0,0
01101,"064  ","0640941","ホッカイドウ","サッポロシチュウオウク","アサヒガオカ","北海道","札幌市中央区","旭ケ丘",0,0,1,0,0,0
01101,"060  ","0600041","ホッカイドウ","サッポロシチュウオウク","オオドオリヒガシ","北海道","札幌市中央区","大通東",0,0,1,0,0,0
01101,"060  ","0600042","ホッカイドウ","サッポロシチュウオウク","オオドオリニシ(1−19チョウメ)","北海道","札幌市中央区","大通西(1〜19丁目)",1,0,1,0,0,0
01101,"064  ","0640820","ホッカイドウ","サッポロシチュウオウク","オオドオリニシ(20−28チョウメ)","北海道","札幌市中央区","大通西(20〜28丁目)",1,0,1,0,0,0
01101,"060  ","0600031","ホッカイドウ","サッポロシチュウオウク","キタ1ジョウヒガシ","北海道","札幌市中央区","北一条東",0,0,1,0,0,0
01101,"060  ","0600001","ホッカイドウ","サッポロシチュウオウク","キタ1ジョウニシ(1−19チョウメ)","北海道","札幌市中央区","北一条西(1〜19丁目)",1,0,1,0,0,0
01101,"064  ","0640821","ホッカイドウ","サッポロシチュウオウク","キタ1ジョウニシ(20−28チョウメ)","北海道","札幌市中央区","北一条西(20〜28丁目)",1,0,1,0,0,0
01101,"060  ","0600032","ホッカイドウ","サッポロシチュウオウク","キタ2ジョウヒガシ","北海道","札幌市中央区","北二条東",0,0,1,0,0,0
01101,"060  ","0600002","ホッカイドウ","サッポロシチュウオウク","キタ2ジョウニシ(1−19チョウメ)","北海道","札幌市中央区","北二条西(1〜19丁目)",1,0,1,0,0,0
// 以下略

utf_ken_all.csvの各列は以下のようになっていますが、住所検索に必要なのは3列目から9列目です。

1: 全国地方公共団体コード
2: 旧郵便番号(3桁 or 5桁)
3: 郵便番号(7桁)
4: 都道府県名(カタカナ)
5: 市区町村名(カタカナ)
6: 町域名(カタカナ)
7: 都道府県名(漢字)
8: 市区町村名(漢字)
9: 町域名(漢字)
10:一町域が二以上の郵便番号で表される場合の表示(1 or 0)
11:小字毎に番地が起番されている町域の表示(1 or 0)
12:丁目を有する町域の場合の表示(1 or 0)
13:1つの郵便番号で二以上の町域を表す場合の表示(1 or 0)
14:更新の表示(1 or 0)
15:変更理由(1 or 0)

utf_ken_all.csvは分割して使用する

utf_ken_all.csvはファイルサイズが約18.3MBと大きいので、使用する際は分割して使用してください。

utf_ken_all.csvの分割にはNode.jsを使用します。まず、split_csv.jsというファイルを作成して以下のように001.csvから999.csvに分割します。

分割する際に3列目から9列目以外およびダブルクォーテーションは不要なので削除します。

split_csv.js
const fs = require('fs')
const readline = require('readline')
const inputFile = 'utf_ken_all.csv'
const fileStreams = {}
const rl = readline.createInterface({
  input: fs.createReadStream(inputFile),
  crlfDelay: Infinity,
})

rl.on('line', (line) => {
  const columns = line.split(',')
  const code3 = columns[1].replace(/"/g, '').trim().substring(0, 3)
  const selectedColumns = [
    columns[2].replace(/"/g, '').trim(), // 郵便番号
    columns[3].replace(/"/g, '').trim(), // 都道府県カナ
    columns[4].replace(/"/g, '').trim(), // 市区町村カナ
    columns[5].replace(/"/g, '').trim(), // 町域名カナ
    columns[6].replace(/"/g, '').trim(), // 都道府県
    columns[7].replace(/"/g, '').trim(), // 市区町村
    columns[8].replace(/"/g, '').trim(), // 町域名
  ].join(',')

  if (!fileStreams[code3]) {
    fileStreams[code3] = fs.createWriteStream(`${code3}.csv`)
  }
  fileStreams[code3].write(selectedColumns + '\n')
})

rl.on('close', () => {
  Object.values(fileStreams).forEach((stream) => stream.end())
  console.log('ファイルの分割が完了しました')
})

dataというディレクトリを作成して、utf_ken_all.csvをdataとsplit_csv.jsをディレクトリに入れて、cdでdataディレクトリに移動したあとに「node split_csv.js」を実行すると001.csvから999.csvの分割されたCSVファイルが生成されます。

utf_ken_all.csvを分割したCSVファイル一覧

JavaScriptでCSVファイルを読み込む

CSVファイルは用意できたので、あとは以下のようにJavaScriptでCSVファイルを読み込んで表示させれば完成です。

HTML
<h1>JavaScriptでutf_ken_all.csvの分割ファイルから郵便番号を住所変換するサンプル</h1>
<form onsubmit="event.preventDefault();">
  <input type="text" value="1700012" id="zip" inputmode="numeric">
  <button id="search">郵便番号検索</button>
</form>
<div id="error"></div>
<hr>
<input type="text" id="kana" class="w100">
<br><br>
<input type="text" id="address" class="w100">
<script src="fetchCSV.js"></script>
fetchCSV.js
const zip = document.getElementById('zip')
const search = document.getElementById('search')
const kana = document.getElementById('kana')
const address = document.getElementById('address')
const error = document.getElementById('error')

function toNormalNumber(str) {
  str = str.replace(/\-/g, '').trim()
  return str.replace(/[0-9]/g, function (s) {
    return String.fromCharCode(s.charCodeAt(0) - 0xfee0)
  })
}

search.addEventListener('click', () => {
  const postcode = toNormalNumber(zip.value)
  const csvfile = postcode.slice(0, 3)
  kana.value = ''
  address.value = ''

  if (!postcode) return
  if (!/^\d{7}$/.test(postcode)) {
    error.textContent = '郵便番号は7桁の数字です'
    return
  }

  function fetchCSV(file) {
    fetch(`./data/${file}.csv`)
      .then((response) => response.text())
      .then((data) => {
        const parsedData = Array.from(
          data.split('\n').map((line) => line.split(','))
        )
        const filterData = parsedData.find((item) => item[0] === postcode)
        if (!filterData) {
          error.textContent = '存在しない郵便番号です'
          return
        }
        const kanaData = filterData.slice(1, 4).join('')
        const addressData = filterData.slice(4).join('')

        if (!filterData.length || !addressData || /掲載がない場合/.test(addressData)) {
          error.textContent = '存在しない郵便番号です'
        } else {
          error.textContent = ''
          kana.value = kanaData
          address.value = addressData
        }
      })
  }
  fetchCSV(csvfile)
})

JavaScriptでutf_ken_all.csvの分割ファイルから郵便番号を住所変換するサンプル

郵便局のutf_ken_all.csvは定期的に変更されるので、GitHub Actionsで自動的にダウンロードして、自動的に分割してGitHubに反映させるようにすると更新が楽になります。

auto_utf_ken_all_download.yml
name: Download, Extract, and Split JAPANPOST CSV

on:
  workflow_dispatch:
  schedule:
  - cron: '0 0 * * *'

jobs:
  download_and_process_csv:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Create directory for CSV file
        run: mkdir -p data

      - name: Download utf_ken_all.zip
        run: |
          curl -o data/utf_ken_all.zip https://www.post.japanpost.jp/zipcode/dl/utf/zip/utf_ken_all.zip

      - name: Unzip utf_ken_all.zip
        run: |
          sudo apt-get install -y unzip
          unzip -o data/utf_ken_all.zip -d data/

      - name: Verify CSV file extraction
        run: |
          if [ -f data/utf_ken_all.csv ]; then
            echo "CSV file extracted successfully."
          else
            echo "CSV file extraction failed."
            exit 1
          fi

      - name: Setup Node.js
        uses: actions/setup-node@v4

      - name: Install dependencies
        run: npm install

      - name: Run split_csv.js to split CSV file
        run: node data/split_csv.js

      - name: Commit split CSV files to repository
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add *.csv
          git commit -m "Update split CSV files" || echo "No changes to commit"
          git push || echo "Nothing to push"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

可能であればGitHub Actionsで自動化、難しければ手動でNode.jsで分割してサーバーにアップロードして実装すると良いでしょう。