Repository navigation
Conversation
Node.js 20 の非推奨警告に対応。2026年6月16日のデフォルト切り替えに先立ち、 FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true を設定して Node.js 24 に移行する。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NormalizeOaza のデフォルトを true に変更(大字省略は日常的なため) - 丁目なしのハイフンなし番地(例: 567)を Block に抽出するよう修正 - 番地以降の建物名を Remainder に分離(例: 2-1六本木グランドタワー → block=2-1, remainder=六本木グランドタワー) - 番地と建物名の間の半角・全角スペースを Trim するよう修正 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
.NET SDK なしでデータ取得できるよう Dockerfile と .dockerignore を追加。 .gitignore の Dockerfile 除外エントリを削除し、README にDocker 手順を追記。
- SplitStreetBlock に漢字丁目形("一丁目")のパターンを追加: chomeEntries.Chome との前方一致で照合し、chome_n を使って "1丁目" 形式に正規化する。これにより "一丁目1番地1号" などの 漢字入力が正しく street="1丁目" に分割される。 - 丁目省略形("3-...")も chomeEntry.Chome(漢字)ではなく 入力の半角数字を使って返すよう統一("三丁目" → "3丁目")。 - ParseRequest に NormalizeNumber を追加し、GET/POST/TSV 全エンドポイントで AddressParseOptions に渡すよう修正。
blockMatch 適用前に "N番(地?)M号?" → "N-M" へ正規化する前処理を 追加することで "1番20号" → block="1-20" として返せるようにした。 これまでは block="1"、remainder="番20号..." になっていた。
- explicitMatch を「N丁目」のみに絞り、番地・番は street の対象外とした。 日本語住所の構造上、番地/番は地番(block)であり、丁目のような 街路ブロック(street)ではないため。 - blockInput 正規化に "N番(地?)" 単独パターンを追加し、後続数字のない 番/番地 を除去して block 数字のみを残す(例: "7番地" → "7")。 - これにより "二番町7番地5" → street=null, block="7-5" が正しく返る。
NormalizeNumber に U+2212 (MINUS SIGN '−') を追加し、 全角ハイフン等と同様に ASCII ハイフンへ変換するようにした。 同時に bareChomeMatch・blockMatch の正規表現および TrimStart にも U+2212 を追加し、NormalizeNumber=false 時にも対応できるよう修正。
NormalizeNumber に U+30FC (KATAKANA-HIRAGANA PROLONGED SOUND MARK 'ー') を追加し、番地区切りとして使われるケースに対応。 bareChomeMatch・blockMatch の正規表現および TrimStart にも同様に追加。
FindCityByTownAsync の町字検索に t.Name.Length >= 2 の条件を追加。 「東」「中」「上」等の1文字町字は住所の他の部分にも頻出するため、 誤マッチの原因となっていた(例: "東京都東京都..." → 渋谷区「東」に誤ヒット)。
GET/POST/TSV エンドポイントで SplitRemainder をハードコードの true から パラメータ経由に変更。デフォルト値は true のまま後方互換を維持。
- ja.json の読み込みを LoadJaRootAsync に集約し _jaRoot フィールドでキャッシュ - GetCitiesAsync の結果を ConcurrentDictionary でキャッシュ(大量処理時のボトルネック解消) - キャッシュ有効性テスト 3 件追加 - CHANGELOG.md を v0.1.1 向けに更新
「福岡県糟屋郡須惠町」(惠 U+60E0) のように、住所辞書(ja.json)は新字 「須恵町」(恵 U+6075)、実データは旧字という字体の揺れがあると ParseAsync が null を返していた。NFKC では畳み込まれない。 - JaAddressOptions.FoldItaiji(既定 false のオプトイン)を追加。有効時、 入力住所文字列と辞書名称(都道府県・市区町村・町字)の双方に 同じ変換マップを適用してから前方一致照合する。1文字→1文字変換のため オフセット計算は不変。出力の City.Name/Town.Name は辞書の元表記を保持。 - 既定マップを埋め込みリソース Resources/itaiji.tsv として同梱 (惠→恵、舘→館 等、住所に出る異体字を中心に約40件)。 - IItaijiFolder / ItaijiFolder を新設し DI 公開。利用者は ItaijiMapPath、 データディレクトリ直下の itaiji.local.tsv、AdditionalItaiji で追加・上書き可能。 - AddressParseOptions.FoldItaiji(bool?)でリクエスト単位の無効化に対応。 - API:JaAddress:FoldItaiji / JaAddress:ItaijiMapPath 設定、各 /parse エンドポイントの foldItaiji パラメータ、POST /parse の foldItaiji を追加。 - ItaijiFoldingTests を追加。既存テスト・API テストは全て成功。
推移的依存として入っていた Microsoft.OpenApi 2.4.1 に、循環スキーマ参照で スタックオーバーフローする脆弱性(GHSA-v5pm-xwqc-g5wc、高)があるため、 JaAddress.Api に修正版 2.7.5 の直接参照を追加してオーバーライドする。 上位パッケージが安全なバージョンを参照するようになったら削除可。
これまで空だった JaAddress.Integration.Tests に、リポジトリ直下の data/ (DataBuilder が生成する本番相当データ、Git 管理外)をそのまま読み込む 結合テストを追加する。合成フィクスチャを使う JaAddress.Core.Tests と異なり、 実データの件数・表記ゆれ・郡構造を実ファイルで検証する。 RealDataFixture が data/ja.json を親ディレクトリ探索(または環境変数 JAADDRESS_DATA_DIR)で解決し、見つからない環境では Xunit.SkippableFact で 各テストをスキップする。これにより「使用できるテストはありません」警告も解消する。
勤務地テキスト等をBestEffortで解析する際の2つの取りこぼしに対応した。
いずれも「都道府県・市区町村・町字までは取れるがStreet/Blockが空になる」
症状で、呼び出し側(利用側のアプリケーション)が
Street+Block必須のフィルタを持つため出力から欠落していた。
1. 町名の連続重複(例: "東京都港区西麻布西麻布1丁目2番3号")
FindTownが町名を1回消費した残りが再び同じ町名で始まると、
SplitStreetBlockが丁目・番地を抽出できずStreet/Blockが空になっていた。
町字確定後、afterTownが同一町名(2文字以上)で始まる限り読み飛ばす処理を追加。
2. 都道府県名の複数出現(例: "A社(東京都中央区の食堂) 東京都中央区日本橋本石町1-2-3")
FindPrefectureInTextが最初の出現位置だけを採用するため、会社名等に
紛れた都道府県名を掴んで解析失敗していた。BestEffort時は出現する
すべての都道府県位置を候補として解析し、最も情報量の多い
(町字・番地まで取れた)結果を採用するよう変更。
- FindPrefectureInText を FindAllPrefectureOccurrences(全出現位置を
offset昇順で返す)に置き換え
- 都道府県確定後の解析処理を TryParseFromAsync に切り出し、候補ごとに実行
- CompletenessScore(Town+番地=3 / Townのみ=2 / 市区町村のみ=1)で選択、
同点は出現位置が早い方(従来どおり)
単一出現・非BestEffortの場合の挙動は変更なし。
AddressServiceTests に単体テスト、RealDataParseTests に実データ結合テストを追加。
旧町名がマスタに無いケース(例: "銀座西1丁目" ← 1969年に"銀座"へ統合)は
別問題のため本コミットの対象外。
利用側のアプリケーションで「住所を出力する対象なのに住所の出力 ファイルへ出力されなかったレコード」を理由付きで出力するため、 ParseAsync が null を返したときに「都道府県を特定できなかった」のか「市区町村を 特定できなかった」のかを呼び出し側で区別できるようにした。 ParseAsync が null を返す経路は以下の3箇所のみで、失敗理由は2種類に確定的に分類できる。 - 非BestEffort:入力の先頭が都道府県名で始まらない → PrefectureNotFound - BestEffort:入力中に都道府県名が1つも出現しない → PrefectureNotFound - TryParseFromAsync:区名・市区町村名・郡名の省略補正を含めても市区町村を特定できない (BestEffort で全出現位置が失敗した場合を含む) → CityNotFound - AddressParseFailureReason(None / PrefectureNotFound / CityNotFound)と、 結果+失敗理由を持つ AddressParseOutcome を追加 - IAddressService に ParseWithReasonAsync を追加し、AddressService の解析本体を移動。 ParseAsync は ParseWithReasonAsync(...).Result を返すラッパーとし、既存の動作は変更しない - BestEffort で全候補が失敗した場合のデバッグログが「都道府県を特定できませんでした」と なっていたのを実態に合わせ「市区町村を特定できませんでした」に修正 - FakeAddressService(Api.Tests)に ParseWithReasonAsync を実装 - AddressServiceTests に失敗理由ごとのケース(BestEffort ON/OFF)と、ParseAsync と ParseWithReasonAsync の解析結果が一致することのテストを追加 dotnet build・dotnet test(Core 74 / Api 13 / Integration 10)成功を確認。 利用側のアプリケーションも本変更を参照してビルド・テスト成功を確認。
企業データベースの住所1万件の計測で、番地の取りこぼしが判明したため修正する。 - SplitStreetBlock:丁目のある町字で "13-9" のような丁目省略形を調べた際、該当する丁目番号が辞書になくても先頭の数字を 消費していた(日向市「都町」は一丁目のみのため "都町13-9" が Block="9" になっていた)。丁目番号が辞書にある場合だけ 丁目として消費し、ない場合は入力全体を番地として扱う。 - FindTown:町字を Name.Length の降順に調べて最初の一致を返していたため、NormalizeOaza の「大字」を外した一致 (「大字本城」→ 消費2文字)が、より長く一致する町字(「本城東」→ 消費3文字)より先に選ばれていた (北九州市八幡西区「本城東2丁目1-21」が Town=大字本城 になり、丁目・番地を落としていた)。入力の消費文字数で比較し、 最長の町字を選ぶ。消費文字数が同じ場合は従来どおり Name.Length の長い方を優先し、挙動を変えていない。 テスト:辞書にない丁目番号・辞書にある丁目番号の省略形・より長い町字の優先・大字付き正規形の返却・消費文字数が同じ場合の 従来挙動の5件を追加(フィクスチャの吉野町に北九州市八幡西区の町字構成を模した 大字本城/本城/本城東 を追加)。 修正前のコードで追加テストのうち2件(バグの2件)が失敗することを確認。dotnet test 全件成功(Core 79件・Integration 10件・Api 13件)。 効果(同じ1万件を再計測):項目の区切りから作った正解と解析結果の照合キーの一致率が 90.5% → 91.8%(町名のあとが「N丁目」の住所は 99.0% → 99.9%)。TODO.md に「町名・番地の取りこぼし」として経緯・残課題 (小字の扱い、辞書の町名接頭辞による町名未検出)を記録した。
企業データベースの住所1万件の計測(TODO.md「町名・番地の取りこぼし」1.)で、
町字のあとに小字があると小字と番地の両方を Remainder に残していた(`保原町大泉字大地内95-5` → Block なし)。番地の取りこぼしで最多の原因。
出力形式は (a) Koaza プロパティの追加に決定した(Town 名への連結は、片方だけが「字」を省略すると町名が一致しなくなるため不採用)。
- TryParseFromAsync:丁目・番地が取れなかった場合のみ、町字の後ろの小字を次の順で採用し、その後ろを SplitStreetBlock で分割する。
1. 辞書の小字(TownEntry.Koaza、「字」の有無を問わず照合・最長一致)で、直後に丁目・番地が続くか住所がそこで終わるもの
(「字」の付かない小字は建物名等の先頭と偶然一致しうるため、この条件を満たす場合のみ)
2. 辞書にない「字○○」で直後に数字が続くもの(辞書の小字が前半だけに一致する場合もこちらを優先する)
3. 「字」で始まる辞書の小字(直後が建物名等でも採用する)
辞書の小字は入力と同じ数字・ハイフンの正規化と異体字の畳み込みを適用して照合する。Koaza は辞書の表記(2. は入力の表記)。
- AddressParseResult に Koaza を追加。API の /parse 応答(ParseResultDto)と TSV 出力に koaza を追加。
テスト:Core に小字のテスト11件(「字」付き・「字」省略・辞書が「字」なし・全角・辞書にない「字○○」・辞書の小字が前半だけに一致・
番地なし・建物名の先頭と一致する「字」なし小字を読まない・町字の直後が番地なら読まない)、Integration に実データ(伊達市保原町大泉)2件を追加。
フィクスチャの吉野町「大字六田」に小字を追加。TSV ヘッダのテストを更新。dotnet test 全件成功(Core 90件・Integration 12件・Api 13件)。
再計測(同じ1万件):正解と解析結果の照合キーの一致率
91.8% → 97.1%、町名のあとが「字・小字」の行3.9% → 98.8%、「字の付かない小字等」4.4% → 47.4%。番地の不一致 824件 → 291件。
入力側の結果が変わった 534件のうち、修正前に取れていた番地が変わった行は0件。残りの内訳を TODO.md に記録した。
- 辞書の町字名・小字名の漢数字・全角数字を算用数字にした表記とも照合する(美園2条→美園二条、北1条西、古町通5番町、11丁目北、14地割)。 名前の末尾の数字は変換しない。"N丁" で終わる町字が "丁目" の途中まで一致する場合は採用しない(蔵前町2丁目) - 数字を含む辞書の小字(十一丁目北・14地割)は、直後に丁目・番地が続くか住所がそこで終わる場合、丁目・番地より優先して読む - 地番の冠称(甲〜癸)の直後に数字が続く場合は Koaza として読み、番地を取る - 小字のあとの番地は丁目省略形・漢字丁目形として読まない 企業データベースの住所と求人の勤務地の住所の突き合わせで見つかった類型。勤務地の住所20万件を 修正前後で解析し、4,376件(2.2%)の変化を類型ごとに確認(大半は北海道の条・線、堺の丁、京都の号等で町字が取れるようになったもの。 町字・丁目が辞書の正式な表記にそろう変化を含む)。企業データベースの住所42,000件と勤務地の住所の照合キーの一致率は 98.1% → 98.7%
- TODO.md・TODO_ARCHIVE.md:利用側のプロジェクト名・テーブル名・社内のファイルパス・独自の用語を、一般的な説明に書き換える - テスト・コメント:実データ由来の会社名・店舗名とその所在地の番地を、架空の名前(株式会社サンプル 等)と番地に置き換える。 町名の重複・全角数字・括弧内の別の住所等、テストで確かめる特徴はそのまま残す - CLAUDE.md:利用側や社内の固有名詞を書かない旨の注意を追加する
辞書は名前ごとにヶ(4,558か所)・ケ(14,563か所)が混在し(例:町字 `古ケ場`・`三ヶ尻`、市区町村 `茅ヶ崎市`・`横浜市保土ケ谷区`)、 照合が完全一致のため、入力の表記が辞書と違うと町字以下が空になる(市区町村名なら解析失敗)。 - AddressService:異体字の畳み込みと同じく、入力と辞書名称の双方に FoldSmallKe を適用する(FoldItaiji によらず常に有効、 1 文字 → 1 文字)。ひらがなの「が」は畳み込まない - 辞書に同じ町字がヶ・ケ両方の表記で重複している場合(町字どうし 51組。`野向町牛ヶ谷`・`野向町牛ケ谷` 等)、畳み込み後の名前が 同じエントリの丁目・小字をまとめて使う - SmallKeFoldingTests を追加(修正前のコードで 9件が失敗することを確認) 求人の勤務地の住所 718,200件を修正前後で解析し、3,921件が変化(町字が新たに取れた 2,687件、解析失敗 → 成功 775件、 丁目・番地のみ 251件、町字名 191件、市区町村 17件。町字が消えた行は0件)。内訳を TODO に記録し、辞書で大字が小字だけの行に なっている件と島名入りの住所を TODO に追加した
辞書(アドレス・ベース・レジストリ)では島しょ部の町村は都の直下にあり島名はないが、慣習として町村名の前に島名を書くことが多い。 - AddressService:島名の対応表(八丈島 → 八丈町、三宅島 → 三宅村)を持ち、島名のあとに町村名が続けば島名を読み飛ばす。 町村名がなく島名だけ(八丈島三根)の場合は島名を町村名として読み、Corrected を true にする。 町村名が島名を含む町村(利島村・大島町 等)と、辞書で町字になっている小笠原村の父島・母島は対象外 - IslandNameTests・RealDataParseTests に島名入りの住所のテストを追加(修正前のコードで 8件が失敗することを確認) 企業データベースの住所で島名のため解析に失敗していた 2,382件は、すべて町村・町字が取れるようになった。 求人の勤務地の住所 718,200件は修正前後で変化なし
…)にまとめて出力できるようにする
データを別の環境へ配布するときに、1,900 個近い JSON ファイルを個別に扱わずに済むようにする。
- 形式はファイル名の拡張子で判定する(未対応の拡張子は取得前にエラー終了)
- 新しい一時ディレクトリに取得してからまとめるため、以前のデータの残りが混ざらない(--output は使わない)
- アーカイブ内のパスは ja.json・ja/{都道府県名}/{市区町村名}.json で、展開したディレクトリをそのまま DataDirectory に指定できる
- 書き込み途中のファイルが残らないよう、一時ファイルに書いてから置き換える
- zip のファイル名は UTF-8(UTF-8 フラグ付き)で格納する。macOS 標準の unzip はこのフラグを解釈しないため README に注記した
- JaAddress.DataBuilder.Tests を新規作成し、tar.gz / tgz / zip の往復(相対パス・日本語のファイル名)、上書き、
未対応の拡張子のテストを追加。展開先のパスにシンボリックリンクを含むと TarFile.ExtractToDirectoryAsync が
ArgumentOutOfRangeException で失敗するため(macOS の /var)、テストの作業ディレクトリはテストの出力ディレクトリの下にした
- CLI で 1 県分を取得し、.tar.gz / .zip の作成と未対応の拡張子でのエラー終了を確認した
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
0.2.0 のリリースです。変更内容は CHANGELOG.md を参照してください。