Skip to content

Commit 042bf7d

Browse files
authored
Merge pull request #77 from mapbox/1ec5-地址-76
Correct formatted addresses in Chinese
2 parents 1c82133 + a89aba2 commit 042bf7d

File tree

5 files changed

+112
-25
lines changed

5 files changed

+112
-25
lines changed

MapboxGeocoder.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@
5656
DA5170F71CF2582F00CD6DCF /* MBPlacemarkScope.h in Headers */ = {isa = PBXBuildFile; fileRef = DA29C8DE1CEBE90200E48A61 /* MBPlacemarkScope.h */; settings = {ATTRIBUTES = (Public, ); }; };
5757
DA5170F81CF2582F00CD6DCF /* MBPlacemarkScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2EC05B1CED72E900D4BA5D /* MBPlacemarkScope.swift */; };
5858
DA5170F91CF2582F00CD6DCF /* MBRectangularRegion.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E03F11CB0FE0200D1269A /* MBRectangularRegion.swift */; };
59+
DA58D8A11DB2ADDD00530CBB /* forward_valid_zh.json in Resources */ = {isa = PBXBuildFile; fileRef = DA58D8A01DB2ADDD00530CBB /* forward_valid_zh.json */; };
60+
DA58D8A21DB2ADDD00530CBB /* forward_valid_zh.json in Resources */ = {isa = PBXBuildFile; fileRef = DA58D8A01DB2ADDD00530CBB /* forward_valid_zh.json */; };
61+
DA58D8A31DB2ADDD00530CBB /* forward_valid_zh.json in Resources */ = {isa = PBXBuildFile; fileRef = DA58D8A01DB2ADDD00530CBB /* forward_valid_zh.json */; };
5962
DA701C011CB1292C00B0E520 /* GeocoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA701C001CB1292C00B0E520 /* GeocoderTests.swift */; };
6063
DAF158851D03D81600829B35 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAF158841D03D81600829B35 /* Launch Screen.storyboard */; };
6164
DAF158861D03D81600829B35 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAF158841D03D81600829B35 /* Launch Screen.storyboard */; };
@@ -173,6 +176,7 @@
173176
DA5170C11CF253EE00CD6DCF /* MapboxGeocoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MapboxGeocoder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
174177
DA5170CA1CF253EE00CD6DCF /* MapboxGeocoderTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MapboxGeocoderTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
175178
DA5170EB1CF2581900CD6DCF /* MapboxGeocoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MapboxGeocoder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
179+
DA58D8A01DB2ADDD00530CBB /* forward_valid_zh.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = forward_valid_zh.json; sourceTree = "<group>"; };
176180
DA701C001CB1292C00B0E520 /* GeocoderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeocoderTests.swift; sourceTree = "<group>"; };
177181
DAF158841D03D81600829B35 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
178182
DD342B5019A140EE00219F77 /* Geocoder (Swift).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Geocoder (Swift).app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -408,6 +412,7 @@
408412
isa = PBXGroup;
409413
children = (
410414
DA210BAC1CB4BFF7008088FD /* forward_valid.json */,
415+
DA58D8A01DB2ADDD00530CBB /* forward_valid_zh.json */,
411416
DA210BAE1CB4C5A7008088FD /* forward_invalid.json */,
412417
DDF1E85B1BD70E4C00C40C78 /* reverse_valid.json */,
413418
DDF1E85A1BD70E4C00C40C78 /* reverse_invalid.json */,
@@ -725,6 +730,7 @@
725730
DA5170B91CF1B1F900CD6DCF /* forward_invalid.json in Resources */,
726731
DA5170BB1CF1B1F900CD6DCF /* reverse_invalid.json in Resources */,
727732
DA5170BA1CF1B1F900CD6DCF /* reverse_valid.json in Resources */,
733+
DA58D8A21DB2ADDD00530CBB /* forward_valid_zh.json in Resources */,
728734
);
729735
runOnlyForDeploymentPostprocessing = 0;
730736
};
@@ -743,6 +749,7 @@
743749
DA5170E31CF2542B00CD6DCF /* forward_invalid.json in Resources */,
744750
DA5170E51CF2542B00CD6DCF /* reverse_invalid.json in Resources */,
745751
DA5170E41CF2542B00CD6DCF /* reverse_valid.json in Resources */,
752+
DA58D8A31DB2ADDD00530CBB /* forward_valid_zh.json in Resources */,
746753
);
747754
runOnlyForDeploymentPostprocessing = 0;
748755
};
@@ -784,6 +791,7 @@
784791
DDF1E85C1BD70E4C00C40C78 /* reverse_invalid.json in Resources */,
785792
DDF1E85D1BD70E4C00C40C78 /* reverse_valid.json in Resources */,
786793
DA210BAF1CB4C5A7008088FD /* forward_invalid.json in Resources */,
794+
DA58D8A11DB2ADDD00530CBB /* forward_valid_zh.json in Resources */,
787795
);
788796
runOnlyForDeploymentPostprocessing = 0;
789797
};

MapboxGeocoder/MBPlacemark.swift

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,14 @@ public class GeocodedPlacemark: Placemark {
369369
return featureJSON["place_name"] as! String
370370
}
371371

372+
internal var qualifiedNameComponents: [String] {
373+
if qualifiedName.containsString(", ") {
374+
return qualifiedName.componentsSeparatedByString(", ")
375+
}
376+
// Chinese addresses have no commas and are reversed.
377+
return (superiorPlacemarks?.map { $0.name } ?? []).reverse() + [name]
378+
}
379+
372380
public override var location: CLLocation {
373381
let centerCoordinate = CLLocationCoordinate2D(geoJSON: featureJSON["center"] as! [Double])
374382
return CLLocation(coordinate: centerCoordinate)
@@ -392,7 +400,7 @@ public class GeocodedPlacemark: Placemark {
392400
if let houseNumber = featureJSON["address"] as? String where scope == .Address {
393401
let streetName = text
394402
let reversedAddress = "\(streetName) \(houseNumber)"
395-
if qualifiedName.componentsSeparatedByString(", ").contains(reversedAddress) {
403+
if qualifiedNameComponents.contains(reversedAddress) {
396404
return reversedAddress
397405
} else {
398406
return "\(houseNumber) \(streetName)"
@@ -423,9 +431,20 @@ public class GeocodedPlacemark: Placemark {
423431
return propertiesJSON["maki"] as? String
424432
}
425433

434+
private var clippedAddressLines: [String] {
435+
let lines = qualifiedNameComponents
436+
if scope == .Address {
437+
return lines
438+
}
439+
guard qualifiedName.containsString(", ") else {
440+
// Chinese addresses have no commas and are reversed.
441+
return Array(lines.prefix(lines.count))
442+
}
443+
return Array(lines.suffixFrom(1))
444+
}
445+
426446
override var formattedAddressLines: [String] {
427-
let lines = qualifiedName.componentsSeparatedByString(", ")
428-
return scope == .Address ? lines : Array(lines.suffixFrom(1))
447+
return clippedAddressLines
429448
}
430449

431450
#if !os(tvOS)
@@ -471,8 +490,7 @@ public class GeocodedPlacemark: Placemark {
471490
addressDictionary[MBPostalAddressPostalCodeKey] = postalCode?.name
472491
addressDictionary[MBPostalAddressCountryKey] = country?.name
473492
addressDictionary[MBPostalAddressISOCountryCodeKey] = country?.code
474-
let lines = qualifiedName.componentsSeparatedByString(", ")
475-
addressDictionary["formattedAddressLines"] = scope == .Address ? lines : Array(lines.suffixFrom(1))
493+
addressDictionary["formattedAddressLines"] = clippedAddressLines
476494
addressDictionary["name"] = name
477495
addressDictionary["subAdministrativeArea"] = district?.name ?? place?.name
478496
addressDictionary["subLocality"] = neighborhood?.name

MapboxGeocoderTests/ForwardGeocodingTests.swift

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ForwardGeocodingTests: XCTestCase {
2020
}
2121

2222
let geocoder = Geocoder(accessToken: BogusToken)
23-
var addressPlacemark: Placemark! = nil
23+
var addressPlacemark: GeocodedPlacemark! = nil
2424
let options = ForwardGeocodeOptions(query: "1600 pennsylvania ave")
2525
options.allowedISOCountryCodes = ["CA"]
2626
let task = geocoder.geocode(options: options) { (placemarks, attribution, error) in
@@ -41,11 +41,12 @@ class ForwardGeocodingTests: XCTestCase {
4141
XCTAssertEqual(addressPlacemark.description, "Pennsylvania Ave", "forward geocode should populate description")
4242
XCTAssertEqual(addressPlacemark.debugDescription, "Pennsylvania Ave, Wasaga Beach, Ontario L9Z 3A8, Canada", "forward geocode should populate debug description")
4343
XCTAssertEqual(addressPlacemark.name, "Pennsylvania Ave", "forward geocode should populate name")
44+
XCTAssertEqual(addressPlacemark.qualifiedNameComponents, ["Pennsylvania Ave", "Wasaga Beach", "Ontario L9Z 3A8", "Canada"], "forward geocode should populate name")
4445
XCTAssertEqual(addressPlacemark.qualifiedName, "Pennsylvania Ave, Wasaga Beach, Ontario L9Z 3A8, Canada", "forward geocode should populate name")
4546
XCTAssertEqual(addressPlacemark.superiorPlacemarks?.count, 4, "forward geocode should populate superior placemarks")
46-
XCTAssertEqual(addressPlacemark.location?.coordinate.latitude, 44.5047077, "forward geocode should populate location")
47+
XCTAssertEqual(addressPlacemark.location.coordinate.latitude, 44.5047077, "forward geocode should populate location")
4748

48-
XCTAssertEqual(addressPlacemark.location?.coordinate.longitude, -79.9850737, "forward geocode should populate location")
49+
XCTAssertEqual(addressPlacemark.location.coordinate.longitude, -79.9850737, "forward geocode should populate location")
4950
XCTAssertEqual(addressPlacemark.scope, PlacemarkScope.Address, "forward geocode should populate scope")
5051
XCTAssertEqual(addressPlacemark.country?.code, "CA", "forward geocode should populate ISO country code")
5152
XCTAssertEqual(addressPlacemark.country?.name, "Canada", "forward geocode should populate country")
@@ -92,4 +93,62 @@ class ForwardGeocodingTests: XCTestCase {
9293
XCTAssertEqual(task.state, NSURLSessionTaskState.Completed)
9394
}
9495
}
96+
97+
func testValidChineseForwardGeocode() {
98+
let expectation = expectationWithDescription("forward geocode should return results")
99+
100+
stub(isHost("api.mapbox.com")
101+
&& isPath("/geocoding/v5/mapbox.places/hainan.json")
102+
&& containsQueryParams(["country": "cn", "language": "zh", "access_token": BogusToken])) { _ in
103+
let path = NSBundle(forClass: self.dynamicType).pathForResource("forward_valid_zh", ofType: "json")
104+
return OHHTTPStubsResponse(fileAtPath: path!, statusCode: 200, headers: ["Content-Type": "application/vnd.geo+json"])
105+
}
106+
107+
let geocoder = Geocoder(accessToken: BogusToken)
108+
var placemark: GeocodedPlacemark! = nil
109+
let options = ForwardGeocodeOptions(query: "hainan")
110+
options.allowedISOCountryCodes = ["CN"]
111+
options.locale = NSLocale(localeIdentifier: "zh-Hans")
112+
let task = geocoder.geocode(options: options) { (placemarks, attribution, error) in
113+
XCTAssertEqual(placemarks?.count, 3)
114+
placemark = placemarks![0]
115+
116+
XCTAssertEqual(attribution, "NOTICE: © 2016 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service (https://www.mapbox.com/about/maps/). This response and the information it contains may not be retained.")
117+
118+
expectation.fulfill()
119+
}
120+
XCTAssertNotNil(task)
121+
122+
waitForExpectationsWithTimeout(1) { (error) in
123+
XCTAssertNil(error, "Error: \(error)")
124+
XCTAssertEqual(task.state, NSURLSessionTaskState.Completed)
125+
}
126+
127+
XCTAssertEqual(placemark.description, "海南区", "forward geocode should populate description")
128+
XCTAssertEqual(placemark.debugDescription, "中国内蒙古乌海市海南区", "forward geocode should populate debug description")
129+
XCTAssertEqual(placemark.name, "海南区", "forward geocode should populate name")
130+
XCTAssertEqual(placemark.qualifiedNameComponents, ["中国", "内蒙古", "乌海市", "海南区"], "forward geocode in Chinese should reverse address components")
131+
XCTAssertEqual(placemark.qualifiedName, "中国内蒙古乌海市海南区", "forward geocode should populate name")
132+
XCTAssertEqual(placemark.superiorPlacemarks?.count, 3, "forward geocode should populate superior placemarks")
133+
XCTAssertEqual(placemark.location.coordinate.latitude, 39.458115, "forward geocode should populate location")
134+
135+
XCTAssertEqual(placemark.location.coordinate.longitude, 106.820552, "forward geocode should populate location")
136+
XCTAssertEqual(placemark.scope, PlacemarkScope.Place, "forward geocode should populate scope")
137+
XCTAssertEqual(placemark.country?.code, "CN", "forward geocode should populate ISO country code")
138+
XCTAssertEqual(placemark.country?.name, "中国", "forward geocode should populate country")
139+
XCTAssertNil(placemark.postalCode, "forward geocode for place should not populate postal code")
140+
XCTAssertEqual(placemark.administrativeRegion?.name, "内蒙古", "forward geocode should populate administrative region")
141+
XCTAssertEqual(placemark.district?.name, "乌海市", "forward geocode should populate district area")
142+
XCTAssertNil(placemark.place?.name, "forward geocode for place should not populate locality")
143+
XCTAssertNil(placemark.thoroughfare, "forward geocode for place should not populate thoroughfare")
144+
XCTAssertNil(placemark.subThoroughfare, "forward geocode should not populate sub-thoroughfare for street-only result")
145+
146+
XCTAssertNotNil(placemark.addressDictionary)
147+
let addressDictionary = placemark.addressDictionary!
148+
XCTAssertNil(addressDictionary[MBPostalAddressStreetKey])
149+
XCTAssertNil(addressDictionary[MBPostalAddressCityKey])
150+
XCTAssertEqual(addressDictionary[MBPostalAddressStateKey] as? String, "内蒙古", "forward geocode should populate state in address dictionary")
151+
XCTAssertEqual(addressDictionary[MBPostalAddressCountryKey] as? String, "中国", "forward geocode should populate country in address dictionary")
152+
XCTAssertEqual(addressDictionary[MBPostalAddressISOCountryCodeKey] as? String, "CN", "forward geocode should populate ISO country code in address dictionary")
153+
}
95154
}

MapboxGeocoderTests/ReverseGeocodingTests.swift

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ReverseGeocodingTests: XCTestCase {
2020
}
2121

2222
let geocoder = Geocoder(accessToken: BogusToken)
23-
var pointOfInterestPlacemark: Placemark?
23+
var pointOfInterestPlacemark: GeocodedPlacemark! = nil
2424
var placePlacemark: Placemark?
2525
let options = ReverseGeocodeOptions(location: CLLocation(latitude: 37.13284000, longitude: -95.78558000))
2626
let task = geocoder.geocode(options: options) { (placemarks, attribution, error) in
@@ -39,23 +39,24 @@ class ReverseGeocodingTests: XCTestCase {
3939
XCTAssertEqual(task.state, NSURLSessionTaskState.Completed)
4040
}
4141

42-
XCTAssertEqual(pointOfInterestPlacemark?.description, "Jones Jerry", "reverse geocode should populate description")
43-
XCTAssertEqual(pointOfInterestPlacemark?.name, "Jones Jerry", "reverse geocode should populate name")
44-
XCTAssertEqual(pointOfInterestPlacemark?.qualifiedName, "Jones Jerry, 2850 CR 3100, Independence, Kansas 67301, United States", "reverse geocode should populate qualified name")
45-
XCTAssertEqual(pointOfInterestPlacemark?.location?.coordinate.latitude, 37.128003, "reverse geocode should populate location")
46-
XCTAssertEqual(pointOfInterestPlacemark?.location?.coordinate.longitude, -95.782951, "reverse geocode should populate location")
47-
XCTAssertEqual(pointOfInterestPlacemark?.scope, PlacemarkScope.PointOfInterest, "reverse geocode should populate scope")
48-
XCTAssertEqual(pointOfInterestPlacemark?.country?.code, "US", "reverse geocode should populate ISO country code")
49-
XCTAssertEqual(pointOfInterestPlacemark?.country?.name, "United States", "reverse geocode should populate country")
50-
XCTAssertEqual(pointOfInterestPlacemark?.postalCode?.name, "67301", "reverse geocode should populate postal code")
51-
XCTAssertEqual(pointOfInterestPlacemark?.administrativeRegion?.name, "Kansas", "reverse geocode should populate administrative region")
52-
XCTAssertNil(pointOfInterestPlacemark?.district?.name, "reverse geocode in the United States should not populate district")
53-
XCTAssertEqual(pointOfInterestPlacemark?.place?.name, "Independence", "reverse geocode should populate place")
54-
XCTAssertNil(pointOfInterestPlacemark?.thoroughfare, "reverse geocode for POI should not populate thoroughfare")
55-
XCTAssertNil(pointOfInterestPlacemark?.subThoroughfare, "reverse geocode for POI should not populate sub-thoroughfare")
42+
XCTAssertEqual(pointOfInterestPlacemark.description, "Jones Jerry", "reverse geocode should populate description")
43+
XCTAssertEqual(pointOfInterestPlacemark.name, "Jones Jerry", "reverse geocode should populate name")
44+
XCTAssertEqual(pointOfInterestPlacemark.qualifiedNameComponents, ["Jones Jerry", "2850 CR 3100", "Independence", "Kansas 67301", "United States"], "reverse geocode should populate qualified name")
45+
XCTAssertEqual(pointOfInterestPlacemark.qualifiedName, "Jones Jerry, 2850 CR 3100, Independence, Kansas 67301, United States", "reverse geocode should populate qualified name")
46+
XCTAssertEqual(pointOfInterestPlacemark.location.coordinate.latitude, 37.128003, "reverse geocode should populate location")
47+
XCTAssertEqual(pointOfInterestPlacemark.location.coordinate.longitude, -95.782951, "reverse geocode should populate location")
48+
XCTAssertEqual(pointOfInterestPlacemark.scope, PlacemarkScope.PointOfInterest, "reverse geocode should populate scope")
49+
XCTAssertEqual(pointOfInterestPlacemark.country?.code, "US", "reverse geocode should populate ISO country code")
50+
XCTAssertEqual(pointOfInterestPlacemark.country?.name, "United States", "reverse geocode should populate country")
51+
XCTAssertEqual(pointOfInterestPlacemark.postalCode?.name, "67301", "reverse geocode should populate postal code")
52+
XCTAssertEqual(pointOfInterestPlacemark.administrativeRegion?.name, "Kansas", "reverse geocode should populate administrative region")
53+
XCTAssertNil(pointOfInterestPlacemark.district?.name, "reverse geocode in the United States should not populate district")
54+
XCTAssertEqual(pointOfInterestPlacemark.place?.name, "Independence", "reverse geocode should populate place")
55+
XCTAssertNil(pointOfInterestPlacemark.thoroughfare, "reverse geocode for POI should not populate thoroughfare")
56+
XCTAssertNil(pointOfInterestPlacemark.subThoroughfare, "reverse geocode for POI should not populate sub-thoroughfare")
5657

57-
XCTAssertNotNil(pointOfInterestPlacemark?.addressDictionary)
58-
let addressDictionary = pointOfInterestPlacemark?.addressDictionary
58+
XCTAssertNotNil(pointOfInterestPlacemark.addressDictionary)
59+
let addressDictionary = pointOfInterestPlacemark.addressDictionary
5960
XCTAssertEqual(addressDictionary?[MBPostalAddressStreetKey] as? String, "2850 CR 3100", "reverse geocode should populate street in address dictionary")
6061
XCTAssertEqual(addressDictionary?[MBPostalAddressCityKey] as? String, "Independence", "reverse geocode should populate city in address dictionary")
6162
XCTAssertEqual(addressDictionary?[MBPostalAddressStateKey] as? String, "Kansas", "reverse geocode should populate state in address dictionary")

0 commit comments

Comments
 (0)