-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcity.go
192 lines (162 loc) · 4.18 KB
/
city.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//go:generate go run ./jpareacodegen --output data.csv
package jpareacode
import (
"bytes"
_ "embed"
"encoding/csv"
"fmt"
"strconv"
"strings"
"github.com/eukarya-inc/jpareacode/jpareacodepref"
)
const tokyo23ku = "東京都特別区部"
const tokyo23kuCode = 13100
//go:embed data.csv
var data []byte
var Cities []City
var citym = map[string]City{}
var citymr = map[int]City{}
type City struct {
PrefCode int `json:"prefCode"`
CityCode int `json:"cityCode"`
CityName string `json:"cityName"`
WardCode int `json:"wardCode"`
WardName string `json:"wardName"`
}
func (c *City) Code() int {
if c == nil {
return 0
}
if c.WardCode > 0 {
return c.WardCode
}
return c.CityCode
}
func init() {
r := csv.NewReader(bytes.NewBuffer(data))
data, err := r.ReadAll()
if err != nil {
panic(err)
}
var lastCityCode int
var lastCityName string
data = append(data, []string{"13", tokyo23ku, FormatCityCode(tokyo23kuCode)})
for _, record := range data {
if len(record) < 3 {
panic("invalid length")
}
pcode, err := strconv.Atoi(record[0])
if err != nil {
panic("invalid code")
}
code, err := strconv.Atoi(record[2])
if err != nil {
panic("invalid code")
}
var wardCode int
var wardName string
var cityCode int
var cityName string
if !isWard(record[1]) {
cityCode = code
cityName = record[1]
lastCityCode = cityCode
lastCityName = cityName
} else {
if isTokyo23ku(code) {
lastCityCode = tokyo23kuCode
lastCityName = tokyo23ku
}
cityCode = lastCityCode
cityName = lastCityName
wardCode = code
wardName = record[1]
}
city := City{
PrefCode: pcode,
CityCode: cityCode,
CityName: cityName,
WardCode: wardCode,
WardName: wardName,
}
Cities = append(Cities, city)
if isTokyo23ku(code) {
cityName = ""
}
citym[record[0]+cityName+wardName] = city
citymr[code] = city
}
}
// CityByName は、都道府県コードと市区町村名を基に市区町村情報を返します。
func CityByName(prefCode int, cityName, wardName string) *City {
if cityName == tokyo23ku {
cityName = ""
}
k := FormatPrefectureCode(prefCode) + cityName + wardName
c, ok := citym[k]
if !ok {
return nil
}
return &c
}
// CitiesByName は、市区町村名に合致する全ての市区町村情報を返します。
func CitiesByName(name string) (res []City) {
for _, c := range Cities {
if c.CityName == name || c.WardName == name {
res = append(res, c)
}
}
return
}
// CityByCode は、市区町村コードを基に市区町村情報を返します。
func CityByCode(code int) *City {
c, ok := citymr[code]
if !ok {
return nil
}
return &c
}
// CityByCodeString は、市区町村コードの文字列を基に市区町村情報を返します。
func CityByCodeString(code string) *City {
c, _ := strconv.Atoi(code)
return CityByCode(c)
}
// SearchCitiesByName は、都道府県名や市区町村名に部分一致する全ての市区町村情報を返します。
func SearchCitiesByName(name string) (res []City) {
for _, c := range Cities {
prefName := jpareacodepref.PrefectureNameByCodeInt(c.PrefCode)
if strings.Contains(prefName, name) {
res = append(res, c)
continue
}
if strings.Contains(c.CityName, name) || strings.Contains(c.WardName, name) {
res = append(res, c)
}
}
return
}
// FormatCityCode は、intの市区町村名コードをstringに変換します。無効なコードの場合は空文字列が返されます。
func FormatCityCode(code int) string {
if !ValidateCityCode(code) {
return ""
}
return fmt.Sprintf("%05d", code)
}
// ParseCityCode は、stringの市区町村名コードをintに変換します。パースに失敗した場合や無効なコードの場合は0が返されます。
func ParseCityCode(code string) int {
c, _ := strconv.Atoi(code)
if !ValidateCityCode(c) {
return 0
}
return c
}
// ValidateCityCode は、市区町村コードが有効かどうかを返します。
func ValidateCityCode(code int) bool {
return code >= PrefectureMinCode*100 && code <= (PrefectureMaxCode+1)*1000-1
}
func isWard(name string) bool {
return strings.HasSuffix(name, "区")
}
func isTokyo23ku(code int) bool {
return code >= 13101 && code < 13199
}