2

我正在开发一个大量使用不同国家地址的应用程序。我们有很多方法可以输入它们,从导入地址到在地图上放置图钉,再到反向地理编码我们当前的位置。

我目前的项目是正确格式化国际地址:

在美国:

18 Street Name

在挪威:

Street Name 18

我已经想出了很多方法来实例化CNMutablePostalAddressCLPlacemark获得一些很好的结果,我遇到的问题就是这个。

我只想将街道名称和号码作为单行字符串返回:所以: street1: placemarker.thoroughfare, (street name) street2: placemarker.subThoroughfare (street number),

但是 CNPostalAddress 只有一个street属性,因此要使用它,您需要执行以下操作:

cNPostalAddress.street = placemarker.subThoroughfare + " " + placemarker.thoroughfare

这不适用于像挪威这样受人尊敬的国家。

您可以破解它并使用格式化地址中的第一行:

CNPostalAddressFormatter.string(from: placemarker.mailingAddress , style: .mailingAddress)

但这太老套了,我相信它会与像日本这样以不同方式订购邮寄地址的国家/地区决裂。

目前,我什至找不到任何资源可以告诉我哪些国家反转了subThoroughfarethoroughfare因为如果我有这样的列表,我可以手动反转它。

这是我迄今为止管理的一些示例代码:

static func mulitLineAddress(from placemarker: CLPlacemark, detail: AddressDetail) -> String {
    let address = MailingAddress(
        street1: placemarker.thoroughfare,
        street2: placemarker.subThoroughfare,
        city: placemarker.locality,
        state: placemarker.administrativeArea,
        postalCode: placemarker.postalCode,
        countryCode: placemarker.country)

    return self.mulitLineAddress(from: address, detail: detail)
}


static func mulitLineAddress(from mailingAddress: MailingAddress, detail: AddressDetail) -> String {

let address = CNMutablePostalAddress()

let street1 = mailingAddress.street1 ?? ""
let street2 = mailingAddress.street2 ?? ""
let streetSpacing = street1.isEmpty && street2.isEmpty ? "" : " "
let streetFull = street1 + streetSpacing + street2

switch detail {
case .street1:
    address.street = street1
case .street2:
    address.street = street2
case .streetFull:
    address.street = streetFull
case .full:
    address.country = mailingAddress.countryCode ?? ""
    fallthrough
case .withoutCountry:
    address.street = streetFull
    address.city = mailingAddress.city ?? ""
    address.state = mailingAddress.state ?? ""
    address.postalCode = mailingAddress.postalCode ?? ""
}

return CNPostalAddressFormatter.string(from: address, style: .mailingAddress)
}

有任何想法吗?甚至像国家名单这样的资源也可以逆转street1并且street2很有用。

4

2 回答 2

0

CNPostalAddressFormatter有一个有趣的 API 可以获取NSAttributedString其中标识每个地址组件的位置。您可以使用它来提取您想要的信息,例如街道,其中包括正确本地化的次干道和通道,无论它可能存在于邮政地址中的哪个位置。

let addressFormatter = CNPostalAddressFormatter()
let attributedAddress = addressFormatter.attributedString(from: postalAddress, withDefaultAttributes: [:])
let nsString = attributedAddress.string as NSString
let range = NSRange(location: 0, length: nsString.length)

var street: String?

attributedAddress.enumerateAttributes(in: range, options: []) { result, range, stop in
    if let component = result[NSAttributedString.Key(CNPostalAddressPropertyAttribute)] as? String {
        if component == CNPostalAddressStreetKey {
            street = nsString.substring(with: range)
            stop.pointee = true
        }
    }
}

我还向 Apple 提交了反馈,以添加更强大和更灵活的 API:FB8648023 Template API 希望用指定的组件格式化地址,类似于DateFormatter.setLocalizedDateFormatFromTemplate

于 2020-09-07T20:16:38.540 回答
0

我最终采用了混合方法。

对于CLPlacemarkto 来说,CNMutablePostalAddress()这很简单:

cnPostalAddress.street = placemarker.postalAddress?.street

但是,这不适用于任何其他输入法,并且不能修改为与CNMutablePostalAddress()

当从其他来源引入地址信息时,我需要手动完成,这里有一个适用于几个国家的例子:

static private func generateLocalizedStreetAddress(from adderss: MailingAddress) -> String {
    guard adderss.localizedStreet.isEmpty else { return adderss.localizedStreet ?? "" }

    let country = CountryCode.country(for: adderss.countryCode)
    let thoroughfare = adderss.thoroughfare ?? ""
    let subThoroughfare = adderss.subThoroughfare ?? ""
    let delimiter = self.generateDelimiter(from: thoroughfare, and: subThoroughfare, with: country)

    switch country {
    case .belgium, .czechRepublic, .denmark, .finland, .germany, .latvia, .netherlands, .norway, .poland, .portugal, .sweden:
        return thoroughfare + delimiter + subThoroughfare
    default:
        return subThoroughfare + delimiter + thoroughfare
    }
}

static private func generateDelimiter(from thoroughfare: String, and subThoroughfare: String, with country: Country) -> String {
    guard !thoroughfare.isEmpty && !subThoroughfare.isEmpty else { return "" }

    switch country {
    case .spain:
        return ", "
    default:
        return " "
    }
}
于 2020-04-01T02:48:24.437 回答