メインコンテンツへスキップ
住所APIナビ

全角・半角・ハイフンを整える住所正規化の基本

日本の住所でよくある表記ゆれを、安全に直せる範囲だけ直す方法をまとめます。NFKC の副作用、ハイフンの見分け方、長音符を壊さない条件まで、実装できるコード付きで説明します。

情報の最終確認日:ページ更新日:人手による確認待ち

執筆:住所APIナビ編集部

同じ住所でも、3-1-133-1-133ー1ー13 は別の文字列です。突合も検索も外部APIへの問い合わせも、この時点で失敗します。

ここでは安全に直せる範囲だけを直す方法を説明します。判断が必要な部分は直さず、利用者に伝えるという方針です。

動作環境

  • Node.js 24.x / ブラウザ(String.prototype.normalize があれば動きます)
  • TypeScript 5.9(strict)

このページのコードは外部通信をしません。ブラウザ内だけで完結します。

1. NFKC でまとめて潰す

Unicode の互換正規化(NFKC)は、全角数字・半角カナ・合成済み記号を「標準的な形」に寄せます。まずこれを一発かけます。

'東京都新宿区西新宿2-8-1'.normalize('NFKC')
// → '東京都新宿区西新宿2-8-1'

NFKC が直してくれるもの:

入力出力種類
123123全角数字
ABCABC全角英字
 (U+3000) 全角空白
ガーデンガーデン半角カナ
(U+FF0D)-全角ハイフンマイナス

2. 末尾で NFC に戻す

NFKC の途中結果には、分解された形が残ることがあります。 が「 + 濁点」の2文字になっていると、見た目は同じでも === で一致しません。

処理の最後に必ず合成形へ戻します。

const normalized = input.normalize('NFKC') /* …他の処理… */.normalize('NFC')

テストで担保しておくと安全です。

expect(normalized).toBe(normalized.normalize('NFC'))

3. ハイフンを統一する — ただし長音符に注意

住所に混ざるハイフンらしき文字は1種類ではありません。NFKC で全角ハイフンは片付きますが、残りは自分で潰す必要があります。

// 常にハイフンとして扱ってよいもの
const ALWAYS_HYPHEN = /[‐‑‒–—―⁃−﹘﹣]/g
// 目に見えないソフトハイフンは削除する
const SOFT_HYPHEN = /­/g

問題は U+30FC(長音符 です。

'3ー1ー13'    // これはハイフンのつもり
'スカイタワー' // これは日本語の一部

同じ文字なので、無条件に置換すると スカイタワ- になります。建物名が壊れます。

数字に挟まれているときだけハイフンとして扱うのが安全な線引きです。

const PROLONGED_BETWEEN_DIGITS = /(?<=[0-9])ー(?=[0-9])/g
 
export function unifyHyphens(text: string): string {
  return text
    .replace(SOFT_HYPHEN, '')
    .replace(ALWAYS_HYPHEN, '-')
    .replace(PROLONGED_BETWEEN_DIGITS, '-')
}
unifyHyphens('新宿3ー1ー13 コーポ東京')
// → '新宿3-1-13 コーポ東京'   ← 番地だけ変換、建物名はそのまま

後読み((?<=)は Safari 16.4 以降で使えます。それより古い環境を対象にする場合は、replace のコールバックで前後の文字を見る実装に置き換えてください。

4. 郵便番号を 123-4567 に揃える

、区切りのない7桁、空白区切り、全角ハイフン — どれも同じ郵便番号です。

// NFKC とハイフン統一のあとに実行する前提
const POSTAL_PATTERN = /〒?\s*(?<![0-9])([0-9]{3})[\s-]?([0-9]{4})(?![0-9])/
 
export function findPostalCode(text: string): string | null {
  const match = POSTAL_PATTERN.exec(text)
  if (!match) return null
  return `${match[1]}-${match[2]}`
}

(?<![0-9])(?![0-9]) を付けているのは、長い数字の途中から7桁を切り出さないためです。これが無いと 第12345678ビル から 123-4567 を拾ってしまいます。

5. 空白を整える

NFKC で全角空白は半角になっているので、あとは潰すだけです。

text.replace(/[ \t\r\n]+/g, ' ').trim()

空白を全部削ってはいけません。 「西新宿2-8-1 テストビル」の空白は、住所と建物名の区切りとして意味を持っていることがあります。

6. 直してはいけないもの

ここからが本題です。次のものは直さず、指摘するだけにしてください。

都道府県の補完 「大阪市北区…」から「大阪府」を補いたくなりますが、やめてください。同名の自治体や、そもそも入力者が意図的に省いている場合があります。無いことを伝えて、必要なら入力してもらいます。

丁目・番・号の書き換え 2丁目8番1号2-8-1 は相互に変換できそうに見えますが、元の表記に意味がある場合があります。 登記や公的書類の写しを扱うなら特にそうです。

異体字・旧字 (はしごだか)を に、(たつさき)を に変換しないでください。氏名や地名では別の文字として扱われます。ただし外部サービスが扱えないことがあるので、含まれていることは伝えてください。

建物名の切り出し 「どこまでが住所でどこからが建物名か」は、表記だけからは決まりません。判定せず、「建物名が含まれているかもしれません」と伝えるにとどめます。

7. 変更点を必ず見せる

正規化の出力は「形式の候補」であって、正解ではありません。何をどう変えたかを1件ずつ出してください。

type Change = {
  rule: string
  before: string
  after: string
  reason: string // 日本語の説明をそのまま表示する
}

8. 正規化で解決しないこと

正規化しても住所が実在するとは限りません。 「東京都新宿区西新宿9-99-99」はきれいに整いますが、存在するかは別の話です。実在性を判定したい場合は住所検証APIの比較を参照してください。

郵便番号から住所を引くのは正規化ではありません。 それは検索です。郵便番号検索APIの比較が該当します。

関連ページ