【作成メモ】Kotlinで逆ジオコーディング利用時の注事項
Swiftだと特に問題なく街名を取得できていたのですが、kotlinでは躓いたのでメモをしておきます。
■逆ジオコーディングの基本的な流れ
①現在地の経度緯度を取得(これは問題なし)
②取得した経度緯度から住所を取得 ←問題アリ
※備考
「geocoder.getFromLocation」は非奨励になっており、「geocoder.getAddress」で逆ジオコーディングした。
■問題点
「geocoder.getAddress」で取得した住所でなぜか第二町名がnullになっている
具体的には以下がgeocoder.getAddressで取得したAdressのログ(住所は一部編集)です。
addressLinesでは「中野区中野7丁目」と取得できているが、
個別だとなぜか「locality=中野区」の次が「thoroughfare=7丁目」となっている。
Swiftの時は「sublocality」というプロパティがありますが、どうやらなさそう・・・??
たぶんバグなんでしょう。。
Address[addressLines=[0:"日本、〒164-0003 東京都中野区中野7丁目 建物サンプル"],feature=建物サンプル,admin=東京都,sub-admin=null,locality=中野区,thoroughfare=7丁目,postalCode=164-0003,countryCode=JP,countryName=日本,hasLatitude=true,latitude=35.7086545,hasLongitude=true,longitude=139.6836509,phone=null,url=null,extras=null]
■改善案
上記のとおり第一町名と番地は取得できるようなので、
以下の条件で住所の文字列(addressLines)から第二町名を取得することにした。
(そのうちSunLocalityが取得できるかもなので、その可能性を残した)
subLocality
が空で、thoroughfare
とlocality
が空でない場合は、住所の文字列からlocality
とthoroughfare
の間の文字列を抽出。thoroughfare
が空で、locality
が空でない場合は、locality
の後の文字列を抽出。thoroughfare
が空で、subLocality
も空の場合は、locality
を文字列とする。thoroughfare
とsubLocality
、locality
が共に空の場合は、代替の町名「こだま街」を使用。- 文字列は4文字までとし、4文字以上の場合は頭の4文字のみとする。
- 文字列の途中に漢数字が入っている場合はその漢数字の直前までを文字列とする。
以下がそのソースです。
private fun generateSecondChomeName(addressString: String, thoroughfare: String, locality: String, subLocality: String): String {
var secondChomeName = ""
// subLocality が空で、thoroughfare と locality が空でない場合は、住所の文字列から locality と thoroughfare の間の文字列を抽出
if (subLocality.isEmpty() && thoroughfare.isNotEmpty() && locality.isNotEmpty()) {
val startIndex = addressString.indexOf(locality) + locality.length
val endIndex = addressString.indexOf(thoroughfare)
if (startIndex >= 0 && endIndex > startIndex) {
secondChomeName = addressString.substring(startIndex, endIndex)
}
}
// thoroughfare が空で、locality が空でない場合は、locality の後の文字列を抽出
else if (thoroughfare.isEmpty() && locality.isNotEmpty()) {
secondChomeName = locality.substring(4.coerceAtMost(locality.length))
}
// thoroughfare が空で、subLocality も空の場合は、locality を文字列とする
else if (thoroughfare.isEmpty() && subLocality.isEmpty() && locality.isNotEmpty()) {
secondChomeName = locality
}
// thoroughfare が空で、subLocality 、 locality が共に空の場合は、代替の町名「こだま街」を使用
else if (thoroughfare.isEmpty() && subLocality.isEmpty() && locality.isEmpty()) {
secondChomeName = "こだま街"
} else {
// locality が空でなければ追加
if (locality.isNotEmpty()) {
secondChomeName = locality
}
// subLocality が空でなければ追加
if (subLocality.isNotEmpty()) {
secondChomeName = subLocality
}
}
// 文字列が4文字以上の場合は、最初の4文字まで取得
if (secondChomeName.length > 4) {
secondChomeName = secondChomeName.substring(0, 4)
}
// 文字列中に漢数字がある場合、その直前までを抽出
val regex = Regex("[一二三四五六七八九十百千万億兆]+")
val matchResult = regex.find(secondChomeName)
if (matchResult != null) {
secondChomeName = secondChomeName.substring(0, matchResult.range.start)
}
// 英数字の場合は "こだま街" に置き換える
if (secondChomeName.matches(Regex("[a-zA-Z0-9]+"))) {
secondChomeName = "こだま街"
}
return secondChomeName
}
今回は用途として町名を4文字以上使わないのでその辺のコードは不要かも。
そのうちsubLocalityを取得できるようになることを信じて、subLocality.isNotEmpty()を最後に記載。
以上です。
まあ町名を抽出して使うという稀有なケースはなかなかありませんが、
このページに辿り着いた方の参考になれば幸いです。