japanese_address_parser 3.0.5 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -2
- data/Gemfile.lock +6 -6
- data/js/node_modules/.package-lock.json +86 -1
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/lib/cacheRegexes.d.ts +9 -2
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-browser.js +141 -25
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-es.d.ts +3 -0
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-es.js +1922 -0
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-node.d.ts +6 -0
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-node.js +203 -54
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/normalize.d.ts +47 -3
- data/js/node_modules/@geolonia/normalize-japanese-addresses/package.json +9 -5
- data/js/node_modules/@geolonia/normalize-japanese-addresses/rollup.config.ts +9 -0
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/config.ts +1 -0
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/lib/cacheRegexes.ts +71 -11
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/lib/dict.ts +3 -2
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/lib/kan2num.ts +6 -2
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/main-es.ts +4 -0
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/main-node.ts +41 -12
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/normalize.ts +165 -37
- data/js/package-lock.json +7 -7
- data/js/package.json +1 -1
- data/lib/japanese_address_parser/data/03-03206.csv +1 -0
- data/lib/japanese_address_parser/data/04-04421.csv +8 -8
- data/lib/japanese_address_parser/data/05-05203.csv +5 -0
- data/lib/japanese_address_parser/data/08-08222.csv +4 -0
- data/lib/japanese_address_parser/data/11-11442.csv +2 -0
- data/lib/japanese_address_parser/data/13-13225.csv +3 -0
- data/lib/japanese_address_parser/data/14-14134.csv +3 -0
- data/lib/japanese_address_parser/data/15-15104.csv +1 -1
- data/lib/japanese_address_parser/data/15-15222.csv +1 -1
- data/lib/japanese_address_parser/data/15-15225.csv +1 -1
- data/lib/japanese_address_parser/data/18-18202.csv +1 -1
- data/lib/japanese_address_parser/data/22-22102.csv +6 -0
- data/lib/japanese_address_parser/data/23-23202.csv +1 -0
- data/lib/japanese_address_parser/data/23-23207.csv +5 -0
- data/lib/japanese_address_parser/data/23-23213.csv +1 -0
- data/lib/japanese_address_parser/data/23-23236.csv +1 -0
- data/lib/japanese_address_parser/data/25-25206.csv +4 -0
- data/lib/japanese_address_parser/data/27-27212.csv +4 -0
- data/lib/japanese_address_parser/data/28-28108.csv +1 -0
- data/lib/japanese_address_parser/data/28-28204.csv +1 -1
- data/lib/japanese_address_parser/data/28-28226.csv +1 -0
- data/lib/japanese_address_parser/data/29-29201.csv +1 -1
- data/lib/japanese_address_parser/data/34-34207.csv +3 -0
- data/lib/japanese_address_parser/data/35-35215.csv +3 -0
- data/lib/japanese_address_parser/data/38-38204.csv +17 -0
- data/lib/japanese_address_parser/data/40-40131.csv +1 -0
- data/lib/japanese_address_parser/data/40-40342.csv +4 -0
- data/lib/japanese_address_parser/data/44-44201.csv +27 -0
- data/lib/japanese_address_parser/data/46-46201.csv +4 -0
- data/lib/japanese_address_parser/data/47-47205.csv +4 -0
- data/lib/japanese_address_parser/version.rb +1 -1
- metadata +6 -3
@@ -5,7 +5,7 @@ import { currentConfig } from '../config'
|
|
5
5
|
import { __internals } from '../normalize'
|
6
6
|
import { findKanjiNumbers } from '@geolonia/japanese-numeral'
|
7
7
|
|
8
|
-
type PrefectureList = { [key: string]: string[] }
|
8
|
+
export type PrefectureList = { [key: string]: string[] }
|
9
9
|
interface SingleTown {
|
10
10
|
town: string
|
11
11
|
originalTown?: string
|
@@ -13,8 +13,13 @@ interface SingleTown {
|
|
13
13
|
lat: string
|
14
14
|
lng: string
|
15
15
|
}
|
16
|
-
type TownList = SingleTown[]
|
17
|
-
|
16
|
+
export type TownList = SingleTown[]
|
17
|
+
interface SingleAddr {
|
18
|
+
addr: string
|
19
|
+
lat: string | null
|
20
|
+
lng: string | null
|
21
|
+
}
|
22
|
+
export type AddrList = SingleAddr[]
|
18
23
|
interface GaikuListItem {
|
19
24
|
gaiku: string
|
20
25
|
lat: string
|
@@ -40,16 +45,16 @@ let cachedPrefectures: PrefectureList | undefined = undefined
|
|
40
45
|
const cachedTowns: { [key: string]: TownList } = {}
|
41
46
|
const cachedGaikuListItem: { [key: string]: GaikuListItem[] } = {}
|
42
47
|
const cachedResidentials: { [key: string]: ResidentialList } = {}
|
43
|
-
|
44
|
-
|
45
|
-
|
48
|
+
const cachedAddrs: { [key: string]: AddrList } = {} // TODO: use LRU
|
49
|
+
let cachedSameNamedPrefectureCityRegexPatterns: [string, string][] | undefined =
|
50
|
+
undefined
|
46
51
|
|
47
52
|
export const getPrefectures = async () => {
|
48
53
|
if (typeof cachedPrefectures !== 'undefined') {
|
49
54
|
return cachedPrefectures
|
50
55
|
}
|
51
56
|
|
52
|
-
const prefsResp = await __internals.fetch('.json') // ja.json
|
57
|
+
const prefsResp = await __internals.fetch('.json', { level: 1 }) // ja.json
|
53
58
|
const data = (await prefsResp.json()) as PrefectureList
|
54
59
|
return cachePrefectures(data)
|
55
60
|
}
|
@@ -104,6 +109,7 @@ export const getTowns = async (pref: string, city: string) => {
|
|
104
109
|
|
105
110
|
const townsResp = await __internals.fetch(
|
106
111
|
['', encodeURI(pref), encodeURI(city) + '.json'].join('/'),
|
112
|
+
{ level: 3, pref, city },
|
107
113
|
)
|
108
114
|
const towns = (await townsResp.json()) as TownList
|
109
115
|
return (cachedTowns[cacheKey] = towns)
|
@@ -114,7 +120,13 @@ export const getGaikuList = async (
|
|
114
120
|
city: string,
|
115
121
|
town: string,
|
116
122
|
) => {
|
117
|
-
|
123
|
+
if (currentConfig.interfaceVersion > 1) {
|
124
|
+
throw new Error(
|
125
|
+
`Invalid config.interfaceVersion: ${currentConfig.interfaceVersion}'}. Please set config.interfaceVersion to 1.`,
|
126
|
+
)
|
127
|
+
}
|
128
|
+
|
129
|
+
const cacheKey = `${pref}-${city}-${town}-v${currentConfig.interfaceVersion}`
|
118
130
|
const cache = cachedGaikuListItem[cacheKey]
|
119
131
|
if (typeof cache !== 'undefined') {
|
120
132
|
return cache
|
@@ -136,7 +148,13 @@ export const getResidentials = async (
|
|
136
148
|
city: string,
|
137
149
|
town: string,
|
138
150
|
) => {
|
139
|
-
|
151
|
+
if (currentConfig.interfaceVersion > 1) {
|
152
|
+
throw new Error(
|
153
|
+
`Invalid config.interfaceVersion: ${currentConfig.interfaceVersion}'}. Please set config.interfaceVersion to 1.`,
|
154
|
+
)
|
155
|
+
}
|
156
|
+
|
157
|
+
const cacheKey = `${pref}-${city}-${town}-v${currentConfig.interfaceVersion}`
|
140
158
|
const cache = cachedResidentials[cacheKey]
|
141
159
|
if (typeof cache !== 'undefined') {
|
142
160
|
return cache
|
@@ -166,6 +184,34 @@ export const getResidentials = async (
|
|
166
184
|
return (cachedResidentials[cacheKey] = residentials)
|
167
185
|
}
|
168
186
|
|
187
|
+
export const getAddrs = async (pref: string, city: string, town: string) => {
|
188
|
+
if (currentConfig.interfaceVersion < 2) {
|
189
|
+
throw new Error(
|
190
|
+
`Invalid config.interfaceVersion: ${currentConfig.interfaceVersion}'}. Please set config.interfaceVersion to 2 or higher`,
|
191
|
+
)
|
192
|
+
}
|
193
|
+
|
194
|
+
const cacheKey = `${pref}-${city}-${town}-v${currentConfig.interfaceVersion}`
|
195
|
+
const cache = cachedAddrs[cacheKey]
|
196
|
+
if (typeof cache !== 'undefined') {
|
197
|
+
return cache
|
198
|
+
}
|
199
|
+
|
200
|
+
const addrsResp = await __internals.fetch(
|
201
|
+
['', encodeURI(pref), encodeURI(city), encodeURI(town) + '.json'].join('/'),
|
202
|
+
{ level: 8, pref, city, town },
|
203
|
+
)
|
204
|
+
let addrs: AddrList
|
205
|
+
try {
|
206
|
+
addrs = (await addrsResp.json()) as AddrList
|
207
|
+
} catch {
|
208
|
+
addrs = []
|
209
|
+
}
|
210
|
+
|
211
|
+
addrs.sort((res1, res2) => res1.addr.length - res2.addr.length)
|
212
|
+
return (cachedAddrs[cacheKey] = addrs)
|
213
|
+
}
|
214
|
+
|
169
215
|
// 十六町 のように漢数字と町が連結しているか
|
170
216
|
const isKanjiNumberFollewedByCho = (targetTownName: string) => {
|
171
217
|
const xCho = targetTownName.match(/.町/g)
|
@@ -260,15 +306,29 @@ export const getTownRegexPatterns = async (pref: string, city: string) => {
|
|
260
306
|
const _pattern = `(${patterns.join(
|
261
307
|
'|',
|
262
308
|
)})((丁|町)目?|番(町|丁)|条|軒|線|の町?|地割|号|[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━])`
|
263
|
-
|
264
309
|
return _pattern // デバッグのときにめんどくさいので変数に入れる。
|
265
310
|
},
|
266
311
|
),
|
267
312
|
)
|
268
|
-
|
269
313
|
return [town, pattern]
|
270
314
|
}) as [SingleTown, string][]
|
271
315
|
|
316
|
+
// X丁目の丁目なしの数字だけ許容するため、最後に数字だけ追加していく
|
317
|
+
for (const town of towns) {
|
318
|
+
const chomeMatch = town.town.match(
|
319
|
+
/([^一二三四五六七八九十]+)([一二三四五六七八九十]+)(丁目?)/,
|
320
|
+
)
|
321
|
+
if (!chomeMatch) {
|
322
|
+
continue
|
323
|
+
}
|
324
|
+
const chomeNamePart = chomeMatch[1]
|
325
|
+
const chomeNum = chomeMatch[2]
|
326
|
+
const pattern = toRegexPattern(
|
327
|
+
`^${chomeNamePart}(${chomeNum}|${kan2num(chomeNum)})`,
|
328
|
+
)
|
329
|
+
patterns.push([town, pattern])
|
330
|
+
}
|
331
|
+
|
272
332
|
cachedTownRegexes.set(`${pref}-${city}`, patterns)
|
273
333
|
return patterns
|
274
334
|
}
|
@@ -1,8 +1,8 @@
|
|
1
1
|
// JIS 第2水準 => 第1水準 及び 旧字体 => 新字体
|
2
|
-
const JIS_OLD_KANJI = '
|
2
|
+
const JIS_OLD_KANJI = '亞,圍,壹,榮,驛,應,櫻,假,會,懷,覺,樂,陷,歡,氣,戲,據,挾,區,徑,溪,輕,藝,儉,圈,權,嚴,恆,國,齋,雜,蠶,殘,兒,實,釋,從,縱,敍,燒,條,剩,壤,釀,眞,盡,醉,髓,聲,竊,淺,錢,禪,爭,插,騷,屬,對,滯,擇,單,斷,癡,鑄,敕,鐵,傳,黨,鬪,屆,腦,廢,發,蠻,拂,邊,瓣,寶,沒,滿,藥,餘,樣,亂,兩,禮,靈,爐,灣,惡,醫,飮,營,圓,歐,奧,價,繪,擴,學,罐,勸,觀,歸,犧,擧,狹,驅,莖,經,繼,缺,劍,檢,顯,廣,鑛,碎,劑,參,慘,絲,辭,舍,壽,澁,肅,將,證,乘,疊,孃,觸,寢,圖,穗,樞,齊,攝,戰,潛,雙,莊,裝,藏,續,體,臺,澤,膽,彈,蟲,廳,鎭,點,燈,盜,獨,貳,霸,賣,髮,祕,佛,變,辯,豐,飜,默,與,譽,謠,覽,獵,勵,齡,勞,壓,爲,隱,衞,鹽,毆,穩,畫,壞,殼,嶽,卷,關,顏,僞,舊,峽,曉,勳,惠,螢,鷄,縣,險,獻,驗,效,號,濟,册,棧,贊,齒,濕,寫,收,獸,處,稱,奬,淨,繩,讓,囑,愼,粹,隨,數,靜,專,踐,纖,壯,搜,總,臟,墮,帶,瀧,擔,團,遲,晝,聽,遞,轉,當,稻,讀,惱,拜,麥,拔,濱,竝,辨,舖,襃,萬,譯,豫,搖,來,龍,壘,隸,戀,樓,鰺,鶯,蠣,攪,竈,灌,諫,頸,礦,蘂,靱,賤,壺,礪,檮,濤,邇,蠅,檜,儘,藪,籠,彌,麩'.split(
|
3
3
|
/,/,
|
4
4
|
)
|
5
|
-
const JIS_NEW_KANJI = '
|
5
|
+
const JIS_NEW_KANJI = '亜,囲,壱,栄,駅,応,桜,仮,会,懐,覚,楽,陥,歓,気,戯,拠,挟,区,径,渓,軽,芸,倹,圏,権,厳,恒,国,斎,雑,蚕,残,児,実,釈,従,縦,叙,焼,条,剰,壌,醸,真,尽,酔,髄,声,窃,浅,銭,禅,争,挿,騒,属,対,滞,択,単,断,痴,鋳,勅,鉄,伝,党,闘,届,脳,廃,発,蛮,払,辺,弁,宝,没,満,薬,余,様,乱,両,礼,霊,炉,湾,悪,医,飲,営,円,欧,奥,価,絵,拡,学,缶,勧,観,帰,犠,挙,狭,駆,茎,経,継,欠,剣,検,顕,広,鉱,砕,剤,参,惨,糸,辞,舎,寿,渋,粛,将,証,乗,畳,嬢,触,寝,図,穂,枢,斉,摂,戦,潜,双,荘,装,蔵,続,体,台,沢,胆,弾,虫,庁,鎮,点,灯,盗,独,弐,覇,売,髪,秘,仏,変,弁,豊,翻,黙,与,誉,謡,覧,猟,励,齢,労,圧,為,隠,衛,塩,殴,穏,画,壊,殻,岳,巻,関,顔,偽,旧,峡,暁,勲,恵,蛍,鶏,県,険,献,験,効,号,済,冊,桟,賛,歯,湿,写,収,獣,処,称,奨,浄,縄,譲,嘱,慎,粋,随,数,静,専,践,繊,壮,捜,総,臓,堕,帯,滝,担,団,遅,昼,聴,逓,転,当,稲,読,悩,拝,麦,抜,浜,並,弁,舗,褒,万,訳,予,揺,来,竜,塁,隷,恋,楼,鯵,鴬,蛎,撹,竃,潅,諌,頚,砿,蕊,靭,賎,壷,砺,梼,涛,迩,蝿,桧,侭,薮,篭,弥,麸'.split(
|
6
6
|
/,/,
|
7
7
|
)
|
8
8
|
|
@@ -29,6 +29,7 @@ export const toRegexPattern = (string: string) => {
|
|
29
29
|
_str = _str
|
30
30
|
.replace(/三栄町|四谷三栄町/g, '(三栄町|四谷三栄町)')
|
31
31
|
.replace(/鬮野川|くじ野川|くじの川/g, '(鬮野川|くじ野川|くじの川)')
|
32
|
+
.replace(/柿碕町|柿さき町/g, '(柿碕町|柿さき町)')
|
32
33
|
.replace(/通り|とおり/g, '(通り|とおり)')
|
33
34
|
.replace(/埠頭|ふ頭/g, '(埠頭|ふ頭)')
|
34
35
|
.replace(/番町|番丁/g, '(番町|番丁)')
|
@@ -3,8 +3,12 @@ import { kanji2number, findKanjiNumbers } from '@geolonia/japanese-numeral'
|
|
3
3
|
export const kan2num = (string: string) => {
|
4
4
|
const kanjiNumbers = findKanjiNumbers(string)
|
5
5
|
for (let i = 0; i < kanjiNumbers.length; i++) {
|
6
|
-
|
7
|
-
|
6
|
+
try {
|
7
|
+
// @ts-ignore
|
8
|
+
string = string.replace(kanjiNumbers[i], kanji2number(kanjiNumbers[i]));
|
9
|
+
} catch (error) {
|
10
|
+
// ignore
|
11
|
+
}
|
8
12
|
}
|
9
13
|
|
10
14
|
return string
|
@@ -1,26 +1,55 @@
|
|
1
1
|
import * as Normalize from './normalize'
|
2
2
|
import { promises as fs } from 'fs'
|
3
3
|
import unfetch from 'isomorphic-unfetch'
|
4
|
+
import { TransformRequestQuery } from './normalize'
|
4
5
|
|
5
|
-
const
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
fileURL.search = `?geolonia-api-key=${Normalize.config.geoloniaApiKey}`
|
12
|
-
}
|
13
|
-
return unfetch(fileURL.toString())
|
14
|
-
} else if (fileURL.protocol === 'file:') {
|
15
|
-
const filePath = decodeURI(fileURL.pathname)
|
6
|
+
export const requestHandlers = {
|
7
|
+
file: (fileURL: URL) => {
|
8
|
+
const filePath =
|
9
|
+
process.platform === 'win32'
|
10
|
+
? decodeURI(fileURL.pathname).substr(1)
|
11
|
+
: decodeURI(fileURL.pathname)
|
16
12
|
return {
|
17
13
|
json: async () => {
|
18
14
|
const contents = await fs.readFile(filePath)
|
19
15
|
return JSON.parse(contents.toString('utf-8'))
|
20
16
|
},
|
21
17
|
}
|
18
|
+
},
|
19
|
+
http: (fileURL: URL) => {
|
20
|
+
if (Normalize.config.geoloniaApiKey) {
|
21
|
+
fileURL.search = `?geolonia-api-key=${Normalize.config.geoloniaApiKey}`
|
22
|
+
}
|
23
|
+
return unfetch(fileURL.toString())
|
24
|
+
},
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* 正規化のためのデータを取得する
|
29
|
+
* @param input - Path part like '東京都/文京区.json'
|
30
|
+
* @param requestOptions - input を構造化したデータ
|
31
|
+
*/
|
32
|
+
const fetchOrReadFile = async (
|
33
|
+
input: string,
|
34
|
+
requestOptions: TransformRequestQuery = { level: -1 },
|
35
|
+
): Promise<Response | { json: () => Promise<unknown> }> => {
|
36
|
+
const fileURL = new URL(`${Normalize.config.japaneseAddressesApi}${input}`)
|
37
|
+
if (Normalize.config.transformRequest && requestOptions.level !== -1) {
|
38
|
+
const result = await Normalize.config.transformRequest(
|
39
|
+
fileURL,
|
40
|
+
requestOptions,
|
41
|
+
)
|
42
|
+
return {
|
43
|
+
json: async () => Promise.resolve(result),
|
44
|
+
}
|
22
45
|
} else {
|
23
|
-
|
46
|
+
if (fileURL.protocol === 'http:' || fileURL.protocol === 'https:') {
|
47
|
+
return requestHandlers.http(fileURL)
|
48
|
+
} else if (fileURL.protocol === 'file:') {
|
49
|
+
return requestHandlers.file(fileURL)
|
50
|
+
} else {
|
51
|
+
throw new Error(`Unknown URL schema: ${fileURL.protocol}`)
|
52
|
+
}
|
24
53
|
}
|
25
54
|
}
|
26
55
|
|
@@ -9,21 +9,51 @@ import {
|
|
9
9
|
getCityRegexPatterns,
|
10
10
|
getTownRegexPatterns,
|
11
11
|
getSameNamedPrefectureCityRegexPatterns,
|
12
|
+
// interface version 1
|
12
13
|
getResidentials,
|
13
14
|
getGaikuList,
|
15
|
+
// interface version 2
|
16
|
+
getAddrs,
|
17
|
+
PrefectureList,
|
18
|
+
TownList,
|
19
|
+
AddrList,
|
14
20
|
} from './lib/cacheRegexes'
|
15
21
|
import unfetch from 'isomorphic-unfetch'
|
16
22
|
|
23
|
+
type TransformRequestResponse = null | PrefectureList | TownList | AddrList
|
24
|
+
|
25
|
+
export type TransformRequestQuery = {
|
26
|
+
level: number // level = -1 は旧 API。 transformRequestFunction を設定しても無視する
|
27
|
+
pref?: string
|
28
|
+
city?: string
|
29
|
+
town?: string
|
30
|
+
}
|
31
|
+
|
32
|
+
export type TransformRequestFunction = (
|
33
|
+
url: URL,
|
34
|
+
query: TransformRequestQuery,
|
35
|
+
) => TransformRequestResponse | Promise<TransformRequestResponse>
|
36
|
+
|
17
37
|
/**
|
18
38
|
* normalize {@link Normalizer} の動作オプション。
|
19
39
|
*/
|
20
40
|
export interface Config {
|
41
|
+
/**
|
42
|
+
* レスポンス型のバージョン。デフォルト 1
|
43
|
+
* 1 の場合は jyukyo: string, gaiku: string
|
44
|
+
* 2 の場合は addr: string, other: string
|
45
|
+
*/
|
46
|
+
interfaceVersion: number
|
47
|
+
|
21
48
|
/** 住所データを URL 形式で指定。 file:// 形式で指定するとローカルファイルを参照できます。 */
|
22
49
|
japaneseAddressesApi: string
|
23
50
|
|
24
51
|
/** 町丁目のデータを何件までキャッシュするか。デフォルト 1,000 */
|
25
52
|
townCacheSize: number
|
26
53
|
|
54
|
+
/** 住所データへのリクエストを変形するオプション。 interfaceVersion === 2 で有効 */
|
55
|
+
transformRequest?: TransformRequestFunction
|
56
|
+
|
27
57
|
geoloniaApiKey?: string
|
28
58
|
}
|
29
59
|
export const config: Config = currentConfig
|
@@ -31,7 +61,7 @@ export const config: Config = currentConfig
|
|
31
61
|
/**
|
32
62
|
* 住所の正規化結果として戻されるオブジェクト
|
33
63
|
*/
|
34
|
-
|
64
|
+
interface NormalizeResult_v1 {
|
35
65
|
/** 都道府県 */
|
36
66
|
pref: string
|
37
67
|
/** 市区町村 */
|
@@ -46,7 +76,7 @@ export interface NormalizeResult {
|
|
46
76
|
addr: string
|
47
77
|
/** 緯度。データが存在しない場合は null */
|
48
78
|
lat: number | null
|
49
|
-
/**
|
79
|
+
/** 経度。データが存在しない場合は null */
|
50
80
|
lng: number | null
|
51
81
|
/**
|
52
82
|
* 住所文字列をどこまで判別できたかを表す正規化レベル
|
@@ -60,6 +90,34 @@ export interface NormalizeResult {
|
|
60
90
|
level: number
|
61
91
|
}
|
62
92
|
|
93
|
+
type NormalizeResult_v2 = {
|
94
|
+
/** 都道府県 */
|
95
|
+
pref: string
|
96
|
+
/** 市区町村 */
|
97
|
+
city: string
|
98
|
+
/** 町丁目 */
|
99
|
+
town: string
|
100
|
+
/** 住居表示または地番 */
|
101
|
+
addr: string
|
102
|
+
/** 正規化後の住所文字列 */
|
103
|
+
other?: string
|
104
|
+
/** 緯度。データが存在しない場合は null */
|
105
|
+
lat: number | null
|
106
|
+
/** 経度。データが存在しない場合は null */
|
107
|
+
lng: number | null
|
108
|
+
/**
|
109
|
+
* 住所文字列をどこまで判別できたかを表す正規化レベル
|
110
|
+
* - 0 - 都道府県も判別できなかった。
|
111
|
+
* - 1 - 都道府県まで判別できた。
|
112
|
+
* - 2 - 市区町村まで判別できた。
|
113
|
+
* - 3 - 町丁目まで判別できた。
|
114
|
+
* - 8 - 住居表示住所の街区符号・住居番号までの判別または地番住所の判別ができた。
|
115
|
+
*/
|
116
|
+
level: number
|
117
|
+
}
|
118
|
+
|
119
|
+
export type NormalizeResult = NormalizeResult_v1 | NormalizeResult_v2
|
120
|
+
|
63
121
|
/**
|
64
122
|
* 正規化関数の {@link normalize} のオプション
|
65
123
|
*/
|
@@ -92,6 +150,7 @@ export type Normalizer = (
|
|
92
150
|
|
93
151
|
export type FetchLike = (
|
94
152
|
input: string,
|
153
|
+
requestQuery?: TransformRequestQuery,
|
95
154
|
) => Promise<Response | { json: () => Promise<unknown> }>
|
96
155
|
|
97
156
|
const defaultOption = {
|
@@ -143,7 +202,13 @@ const normalizeResidentialPart = async (
|
|
143
202
|
pref: string,
|
144
203
|
city: string,
|
145
204
|
town: string,
|
146
|
-
)
|
205
|
+
): Promise<{
|
206
|
+
gaiku: string
|
207
|
+
jyukyo?: string
|
208
|
+
addr: string
|
209
|
+
lat: string
|
210
|
+
lng: string
|
211
|
+
} | null> => {
|
147
212
|
const [gaikuListItem, residentials] = await Promise.all([
|
148
213
|
getGaikuList(pref, city, town),
|
149
214
|
getResidentials(pref, city, town),
|
@@ -183,6 +248,27 @@ const normalizeResidentialPart = async (
|
|
183
248
|
return null
|
184
249
|
}
|
185
250
|
|
251
|
+
const normalizeAddrPart = async (
|
252
|
+
addr: string,
|
253
|
+
pref: string,
|
254
|
+
city: string,
|
255
|
+
town: string,
|
256
|
+
) => {
|
257
|
+
const addrListItem = await getAddrs(pref, city, town)
|
258
|
+
|
259
|
+
// 住居表示住所、および地番住所が見つからなかった
|
260
|
+
if (addrListItem.length === 0) {
|
261
|
+
return null
|
262
|
+
}
|
263
|
+
|
264
|
+
const addrItem = addrListItem.find((item) => addr.startsWith(item.addr))
|
265
|
+
if (addrItem) {
|
266
|
+
const other = addr.replace(addrItem.addr, '').trim()
|
267
|
+
return { addr: addrItem.addr, other, lat: addrItem.lat, lng: addrItem.lng }
|
268
|
+
}
|
269
|
+
return null
|
270
|
+
}
|
271
|
+
|
186
272
|
export const normalize: Normalizer = async (
|
187
273
|
address,
|
188
274
|
_option = defaultOption,
|
@@ -353,7 +439,7 @@ export const normalize: Normalizer = async (
|
|
353
439
|
'$1 $5',
|
354
440
|
)
|
355
441
|
.replace(
|
356
|
-
/([0-9〇一二三四五六七八九十百千]+)(番地?)([0-9〇一二三四五六七八九十百千]+)
|
442
|
+
/([0-9〇一二三四五六七八九十百千]+)\s*(番地?)\s*([0-9〇一二三四五六七八九十百千]+)\s*号?/,
|
357
443
|
'$1-$3',
|
358
444
|
)
|
359
445
|
.replace(/([0-9〇一二三四五六七八九十百千]+)番地?/, '$1')
|
@@ -378,7 +464,7 @@ export const normalize: Normalizer = async (
|
|
378
464
|
// `-1` のようなケース
|
379
465
|
return kan2num(s)
|
380
466
|
})
|
381
|
-
.replace(/-[^0-9]
|
467
|
+
.replace(/-[^0-9]([0-9〇一二三四五六七八九十百千]+)/, (s) => {
|
382
468
|
// `-あ1` のようなケース
|
383
469
|
return kan2num(zen2han(s))
|
384
470
|
})
|
@@ -392,43 +478,85 @@ export const normalize: Normalizer = async (
|
|
392
478
|
|
393
479
|
addr = patchAddr(pref, city, town, addr)
|
394
480
|
|
395
|
-
// 住居表示住所リストを使い番地号までの正規化を行う
|
396
|
-
if (option.level > 3 && normalized && town) {
|
397
|
-
normalized = await normalizeResidentialPart(addr, pref, city, town)
|
398
|
-
}
|
399
|
-
if (normalized) {
|
400
|
-
lat = parseFloat(normalized.lat)
|
401
|
-
lng = parseFloat(normalized.lng)
|
402
|
-
}
|
403
|
-
|
404
|
-
if (Number.isNaN(lat) || Number.isNaN(lng)) {
|
405
|
-
lat = null
|
406
|
-
lng = null
|
407
|
-
}
|
408
|
-
|
409
481
|
if (pref) level = level + 1
|
410
482
|
if (city) level = level + 1
|
411
483
|
if (town) level = level + 1
|
412
484
|
|
413
|
-
|
414
|
-
pref,
|
415
|
-
city,
|
416
|
-
town,
|
417
|
-
addr,
|
418
|
-
lat,
|
419
|
-
lng,
|
420
|
-
level,
|
485
|
+
if (option.level <= 3 || level < 3) {
|
486
|
+
return { pref, city, town, addr, level, lat, lng }
|
421
487
|
}
|
422
488
|
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
489
|
+
// ======================== Advanced section ========================
|
490
|
+
// これ以下は地番住所または住居表示住所までの正規化・ジオコーディングを行う処理
|
491
|
+
// 現状、インターフェース v1 と v2 が存在する
|
492
|
+
// japanese-addresses のフォーマット、および normalize 関数の戻り値が異なる
|
493
|
+
// 将来的に v2 に統一することを検討中
|
494
|
+
// ==================================================================
|
495
|
+
|
496
|
+
// v2 のインターフェース
|
497
|
+
if (currentConfig.interfaceVersion === 2) {
|
498
|
+
const normalizedAddrPart = await normalizeAddrPart(addr, pref, city, town)
|
499
|
+
let other = undefined
|
500
|
+
if (normalizedAddrPart) {
|
501
|
+
addr = normalizedAddrPart.addr
|
502
|
+
if (normalizedAddrPart.other) {
|
503
|
+
other = normalizedAddrPart.other
|
504
|
+
}
|
505
|
+
if (normalizedAddrPart.lat !== null)
|
506
|
+
lat = parseFloat(normalizedAddrPart.lat)
|
507
|
+
if (normalizedAddrPart.lng !== null)
|
508
|
+
lng = parseFloat(normalizedAddrPart.lng)
|
509
|
+
level = 8
|
510
|
+
}
|
511
|
+
const result: NormalizeResult_v2 = {
|
512
|
+
pref,
|
513
|
+
city,
|
514
|
+
town,
|
515
|
+
addr,
|
516
|
+
level,
|
517
|
+
lat,
|
518
|
+
lng,
|
519
|
+
}
|
520
|
+
if (other) {
|
521
|
+
result.other = other
|
522
|
+
}
|
523
|
+
return result
|
524
|
+
} else if (currentConfig.interfaceVersion === 1) {
|
525
|
+
// 住居表示住所リストを使い番地号までの正規化を行う
|
526
|
+
if (option.level > 3 && normalized && town) {
|
527
|
+
normalized = await normalizeResidentialPart(addr, pref, city, town)
|
528
|
+
}
|
529
|
+
if (normalized) {
|
530
|
+
lat = parseFloat(normalized.lat)
|
531
|
+
lng = parseFloat(normalized.lng)
|
532
|
+
}
|
533
|
+
|
534
|
+
if (Number.isNaN(lat) || Number.isNaN(lng)) {
|
535
|
+
lat = null
|
536
|
+
lng = null
|
537
|
+
}
|
538
|
+
|
539
|
+
const result: NormalizeResult_v1 = {
|
540
|
+
pref,
|
541
|
+
city,
|
542
|
+
town,
|
543
|
+
addr,
|
544
|
+
lat,
|
545
|
+
lng,
|
546
|
+
level,
|
547
|
+
}
|
548
|
+
if (normalized && 'gaiku' in normalized) {
|
549
|
+
result.addr = normalized.addr
|
550
|
+
result.gaiku = normalized.gaiku
|
551
|
+
result.level = 7
|
552
|
+
}
|
553
|
+
if (normalized && 'jyukyo' in normalized) {
|
554
|
+
result.jyukyo = normalized.jyukyo
|
555
|
+
result.level = 8
|
556
|
+
}
|
432
557
|
|
433
|
-
|
558
|
+
return result
|
559
|
+
} else {
|
560
|
+
throw new Error('invalid interfaceVersion')
|
561
|
+
}
|
434
562
|
}
|
data/js/package-lock.json
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
"": {
|
7
7
|
"name": "japanese_address_parser",
|
8
8
|
"dependencies": {
|
9
|
-
"@geolonia/normalize-japanese-addresses": "^2.
|
9
|
+
"@geolonia/normalize-japanese-addresses": "^2.9.2"
|
10
10
|
},
|
11
11
|
"devDependencies": {}
|
12
12
|
},
|
@@ -16,9 +16,9 @@
|
|
16
16
|
"integrity": "sha512-xzSsIHhyyjqNpW8qSh5bFMu3FJvyJGBbNZ/t8clPHkigjUdZ7Ck8wkzCkcwlVd00RkoHwGDLnvXx5W0WiGK0TQ=="
|
17
17
|
},
|
18
18
|
"node_modules/@geolonia/normalize-japanese-addresses": {
|
19
|
-
"version": "2.
|
20
|
-
"resolved": "https://registry.npmjs.org/@geolonia/normalize-japanese-addresses/-/normalize-japanese-addresses-2.
|
21
|
-
"integrity": "sha512-
|
19
|
+
"version": "2.9.2",
|
20
|
+
"resolved": "https://registry.npmjs.org/@geolonia/normalize-japanese-addresses/-/normalize-japanese-addresses-2.9.2.tgz",
|
21
|
+
"integrity": "sha512-sbeV/seJ/ue6pn2sLo+Ccunl6eB3yNhrUIzNpT2IiR9Fw6fW5f1lLdApODqhTmz++xr1dyPwZOzTXCGEaXejDA==",
|
22
22
|
"dependencies": {
|
23
23
|
"@geolonia/japanese-numeral": "^0.1.16",
|
24
24
|
"isomorphic-unfetch": "^3.1.0",
|
@@ -101,9 +101,9 @@
|
|
101
101
|
"integrity": "sha512-xzSsIHhyyjqNpW8qSh5bFMu3FJvyJGBbNZ/t8clPHkigjUdZ7Ck8wkzCkcwlVd00RkoHwGDLnvXx5W0WiGK0TQ=="
|
102
102
|
},
|
103
103
|
"@geolonia/normalize-japanese-addresses": {
|
104
|
-
"version": "2.
|
105
|
-
"resolved": "https://registry.npmjs.org/@geolonia/normalize-japanese-addresses/-/normalize-japanese-addresses-2.
|
106
|
-
"integrity": "sha512-
|
104
|
+
"version": "2.9.2",
|
105
|
+
"resolved": "https://registry.npmjs.org/@geolonia/normalize-japanese-addresses/-/normalize-japanese-addresses-2.9.2.tgz",
|
106
|
+
"integrity": "sha512-sbeV/seJ/ue6pn2sLo+Ccunl6eB3yNhrUIzNpT2IiR9Fw6fW5f1lLdApODqhTmz++xr1dyPwZOzTXCGEaXejDA==",
|
107
107
|
"requires": {
|
108
108
|
"@geolonia/japanese-numeral": "^0.1.16",
|
109
109
|
"isomorphic-unfetch": "^3.1.0",
|
data/js/package.json
CHANGED
@@ -353,6 +353,7 @@ name,name_kana,name_romaji,nickname,latitude,longitude
|
|
353
353
|
下鬼柳,シモオニヤナギ,SHIMONIYANAGI,十六地割,39.266345,141.096501
|
354
354
|
下鬼柳,シモオニヤナギ,SHIMONIYANAGI,十四地割,39.266478,141.102455
|
355
355
|
下鬼柳,シモオニヤナギ,SHIMONIYANAGI,四地割,39.282827,141.091036
|
356
|
+
しらゆり,シラユリ,SHIRAYURI,,,
|
356
357
|
新穀町一丁目,シンコクチョウ 1,SHINKOKUCHO 1,,39.289124,141.112788
|
357
358
|
新穀町二丁目,シンコクチョウ 2,SHINKOKUCHO 2,,39.289984,141.110576
|
358
359
|
諏訪町一丁目,スワチョウ 1,SUWACHO 1,,39.286243,141.11941
|
@@ -1,12 +1,4 @@
|
|
1
1
|
name,name_kana,name_romaji,nickname,latitude,longitude
|
2
|
-
落合桧和田,,,,38.430514,140.947568
|
3
|
-
落合桧和田,,,中道,38.430873,140.92928
|
4
|
-
落合桧和田,,,八幡堂,38.427406,140.938836
|
5
|
-
落合桧和田,,,千刈田,38.430733,140.932626
|
6
|
-
落合桧和田,,,新高原,38.432263,140.930077
|
7
|
-
落合桧和田,,,糯田,38.429822,140.932751
|
8
|
-
落合桧和田,,,遠浦,38.431684,140.925735
|
9
|
-
落合桧和田,,,高原,38.430335,140.93046
|
10
2
|
落合相川,オチアイアイカワ,OCHIAI AIKAWA,,38.442109,140.921086
|
11
3
|
落合相川,オチアイアイカワ,OCHIAI AIKAWA,塚越,38.438884,140.930493
|
12
4
|
落合相川,オチアイアイカワ,OCHIAI AIKAWA,塚越三番,38.439941,140.935737
|
@@ -31,6 +23,14 @@ name,name_kana,name_romaji,nickname,latitude,longitude
|
|
31
23
|
落合蒜袋,オチアイヒルブクロ,OCHIAI HIRUBUKURO,菱柄,38.447649,140.911786
|
32
24
|
落合蒜袋,オチアイヒルブクロ,OCHIAI HIRUBUKURO,行屋下,38.449988,140.909907
|
33
25
|
落合蒜袋,オチアイヒルブクロ,OCHIAI HIRUBUKURO,長町,38.449781,140.908786
|
26
|
+
落合桧和田,オチアイヒワダ,,,38.430514,140.947568
|
27
|
+
落合桧和田,オチアイヒワダ,,中道,38.430873,140.92928
|
28
|
+
落合桧和田,オチアイヒワダ,,八幡堂,38.427406,140.938836
|
29
|
+
落合桧和田,オチアイヒワダ,,千刈田,38.430733,140.932626
|
30
|
+
落合桧和田,オチアイヒワダ,,新高原,38.432263,140.930077
|
31
|
+
落合桧和田,オチアイヒワダ,,糯田,38.429822,140.932751
|
32
|
+
落合桧和田,オチアイヒワダ,,遠浦,38.431684,140.925735
|
33
|
+
落合桧和田,オチアイヒワダ,,高原,38.430335,140.93046
|
34
34
|
落合報恩寺,オチアイホウオンジ,OCHIAI HOONJI,,38.443497,140.953906
|
35
35
|
落合報恩寺,オチアイホウオンジ,OCHIAI HOONJI,大久保,38.44271,140.944656
|
36
36
|
落合報恩寺,オチアイホウオンジ,OCHIAI HOONJI,竹沢下,38.438117,140.944617
|
@@ -43,9 +43,13 @@ name,name_kana,name_romaji,nickname,latitude,longitude
|
|
43
43
|
猪岡,イノオカ,INOKA,水上,39.31756,140.521665
|
44
44
|
猪岡,イノオカ,INOKA,長瀞,39.315335,140.519002
|
45
45
|
梅の木町,ウメノキマチ,UMENOKIMACHI,,39.315702,140.557751
|
46
|
+
駅西一丁目,エキニシ 1,EKINISHI 1,,,
|
47
|
+
駅西二丁目,エキニシ 2,EKINISHI 2,,,
|
48
|
+
駅西三丁目,エキニシ 3,EKINISHI 3,,,
|
46
49
|
駅前町,エキマエチョウ,EKIMAECHO,,39.308784,140.561408
|
47
50
|
駅南一丁目,エキミナミ 1,EKIMINAMI 1,,39.302415,140.56071
|
48
51
|
駅南二丁目,エキミナミ 2,EKIMINAMI 2,,39.302577,140.558314
|
52
|
+
駅南三丁目,エキミナミ 3,EKIMINAMI 3,,,
|
49
53
|
追廻一丁目,オイマワシ 1,OIMAWASHI 1,,39.332247,140.568572
|
50
54
|
追廻二丁目,オイマワシ 2,OIMAWASHI 2,,39.331959,140.570628
|
51
55
|
追廻三丁目,オイマワシ 3,OIMAWASHI 3,,39.334844,140.572056
|
@@ -408,6 +412,7 @@ name,name_kana,name_romaji,nickname,latitude,longitude
|
|
408
412
|
三本柳,サンボンヤナギ,SAMBONYANAGI,街道下,39.321213,140.538111
|
409
413
|
三本柳,サンボンヤナギ,SAMBONYANAGI,馬場尻,39.324461,140.53328
|
410
414
|
三枚橋一丁目,サンマイバシ 1,SAMMAIBASHI 1,,39.313272,140.558151
|
415
|
+
三枚橋二丁目,サンマイバシ 2,SANMAIBASHI 2,,,
|
411
416
|
静町,シズカマチ,SHIZUKAMACHI,,39.332264,140.545279
|
412
417
|
静町,シズカマチ,SHIZUKAMACHI,北小屋,39.336115,140.543985
|
413
418
|
静町,シズカマチ,SHIZUKAMACHI,払小屋,39.334205,140.543283
|
@@ -76,6 +76,10 @@ name,name_kana,name_romaji,nickname,latitude,longitude
|
|
76
76
|
鉢形台一丁目,ハチガタダイ 1,HACHIGATADAI 1,,35.96364,140.647669
|
77
77
|
鉢形台二丁目,ハチガタダイ 2,HACHIGATADAI 2,,35.961016,140.648239
|
78
78
|
鉢形台三丁目,ハチガタダイ 3,HACHIGATADAI 3,,35.95818,140.649236
|
79
|
+
平井東一丁目,ヒライヒガシ 1,HIRAIHIGASHI 1,,,
|
80
|
+
平井東二丁目,ヒライヒガシ 2,HIRAIHIGASHI 2,,,
|
81
|
+
平井東三丁目,ヒライヒガシ 3,HIRAIHIGASHI 3,,,
|
82
|
+
平井東四丁目,ヒライヒガシ 4,HIRAIHIGASHI 4,,,
|
79
83
|
緑ヶ丘一丁目,ミドリガオカ 1,MIDORIGAOKA 1,,35.973731,140.623658
|
80
84
|
緑ヶ丘二丁目,ミドリガオカ 2,MIDORIGAOKA 2,,35.972016,140.622091
|
81
85
|
緑ヶ丘三丁目,ミドリガオカ 3,MIDORIGAOKA 3,,35.971853,140.618483
|