I'm working on a function that gets the country code from the phone, but when I get the country code it consists of 2 letters, but I want it to return three letters.
For example US -> USA
In Android, java supports converting from 2 characters to 3 characters with the following code:
Locale locale = new Locale("en", countryCode);
return locale.getISO3Country();
But in iOS with Objective-C I don't know how to convert it, so can anyone help me to solve this problem?
for the sake of standardisation there is no ISO 3166-1 alpha-3 code on apple platforms to convert to. More the other way around, you could use a 3 letter code and still find the 2 letter code.
and if you want to keep at least some consistency to your android code then you need to implement some LUT table supporting this off-standard feature yourself. The available list is not very long anyway (256 codes).
NSArray *isoCountrys = [NSLocale ISOCountryCodes];
for (NSString *code in isoCountrys) {
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:code];
// country name in native language
NSString *country = [locale localizedStringForCountryCode:code];
NSString *iso3 = LUTisoA3counterpartCodes[code];
NSLog(#"%# %# %# %#",code, iso3, country, locale.localeIdentifier);
}
Docu NSLocale -localizedStringForCountryCode:
Docu NSLocale -countryCode
the LUT could look like.. and is much better stored in a plist then the following runtime allocated dictionary.
NSDictionary *LUTisoA3counterpartCodes = #{
#"AC":#"SHN",#"AW":#"ABW",#"AF":#"AFG",#"AO":#"AGO",#"AI":#"AIA",#"AX":#"ALA",
#"AL":#"ALB",#"AD":#"AND",#"AE":#"ARE",#"AR":#"ARG",#"AM":#"ARM",#"AS":#"ASM",
#"AQ":#"ATA",#"TF":#"ATF",#"AG":#"ATG",#"AU":#"AUS",#"AT":#"AUT",#"AZ":#"AZE",
#"BI":#"BDI",#"BE":#"BEL",#"BJ":#"BEN",#"BQ":#"BES",#"BF":#"BFA",#"BD":#"BGD",
#"BG":#"BGR",#"BH":#"BHR",#"BS":#"BHS",#"BA":#"BIH",#"BL":#"BLM",#"BY":#"BLR",
#"BZ":#"BLZ",#"BM":#"BMU",#"BO":#"BOL",#"BR":#"BRA",#"BB":#"BRB",#"BN":#"BRN",
#"BT":#"BTN",#"BV":#"BVT",#"BW":#"BWA",#"CF":#"CAF",#"CA":#"CAN",#"CC":#"CCK",
#"CH":#"CHE",#"CL":#"CHL",#"CN":#"CHN",#"CI":#"CIV",#"CM":#"CMR",#"CD":#"COD",
#"CG":#"COG",#"CK":#"COK",#"CO":#"COL",#"KM":#"COM",#"CV":#"CPV",#"CR":#"CRI",
#"CU":#"CUB",#"CW":#"CUW",#"CX":#"CXR",#"KY":#"CYM",#"CY":#"CYP",#"CZ":#"CZE",
#"DE":#"DEU",#"DJ":#"DJI",#"DM":#"DMA",#"DK":#"DNK",#"DO":#"DOM",#"DZ":#"DZA",
#"EC":#"ECU",#"EG":#"EGY",#"ER":#"ERI",#"EH":#"ESH",#"ES":#"ESP",#"EE":#"EST",
#"ET":#"ETH",#"FI":#"FIN",#"FJ":#"FJI",#"FK":#"FLK",#"FR":#"FRA",#"FO":#"FRO",
#"FM":#"FSM",#"GA":#"GAB",#"GB":#"GBR",#"GE":#"GEO",#"GG":#"GGY",#"GH":#"GHA",
#"GI":#"GIB",#"GN":#"GIN",#"GP":#"GLP",#"GM":#"GMB",#"GW":#"GNB",#"GQ":#"GNQ",
#"GR":#"GRC",#"GD":#"GRD",#"GL":#"GRL",#"GT":#"GTM",#"GF":#"GUF",#"GU":#"GUM",
#"GY":#"GUY",#"HK":#"HKG",#"HM":#"HMD",#"HN":#"HND",#"HR":#"HRV",#"HT":#"HTI",
#"HU":#"HUN",#"ID":#"IDN",#"IM":#"IMN",#"IN":#"IND",#"IO":#"IOT",#"IE":#"IRL",
#"IR":#"IRN",#"IQ":#"IRQ",#"IS":#"ISL",#"IL":#"ISR",#"IT":#"ITA",#"JM":#"JAM",
#"JE":#"JEY",#"JO":#"JOR",#"JP":#"JPN",#"KZ":#"KAZ",#"KE":#"KEN",#"KG":#"KGZ",
#"KH":#"KHM",#"KI":#"KIR",#"KN":#"KNA",#"KR":#"KOR",#"KW":#"KWT",#"LA":#"LAO",
#"LB":#"LBN",#"LR":#"LBR",#"LY":#"LBY",#"LC":#"LCA",#"LI":#"LIE",#"LK":#"LKA",
#"LS":#"LSO",#"LT":#"LTU",#"LU":#"LUX",#"LV":#"LVA",#"MO":#"MAC",#"MF":#"MAF",
#"MA":#"MAR",#"MC":#"MCO",#"MD":#"MDA",#"MG":#"MDG",#"MV":#"MDV",#"MX":#"MEX",
#"MH":#"MHL",#"MK":#"MKD",#"ML":#"MLI",#"MT":#"MLT",#"MM":#"MMR",#"ME":#"MNE",
#"MN":#"MNG",#"MP":#"MNP",#"MZ":#"MOZ",#"MR":#"MRT",#"MS":#"MSR",#"MQ":#"MTQ",
#"MU":#"MUS",#"MW":#"MWI",#"MY":#"MYS",#"YT":#"MYT",#"NA":#"NAM",#"NC":#"NCL",
#"NE":#"NER",#"NF":#"NFK",#"NG":#"NGA",#"NI":#"NIC",#"NU":#"NIU",#"NL":#"NLD",
#"NO":#"NOR",#"NP":#"NPL",#"NR":#"NRU",#"NZ":#"NZL",#"OM":#"OMN",#"PK":#"PAK",
#"PA":#"PAN",#"PN":#"PCN",#"PE":#"PER",#"PH":#"PHL",#"PW":#"PLW",#"PG":#"PNG",
#"PL":#"POL",#"PR":#"PRI",#"KP":#"PRK",#"PT":#"PRT",#"PY":#"PRY",#"PS":#"PSE",
#"PF":#"PYF",#"QA":#"QAT",#"RE":#"REU",#"RO":#"ROU",#"RU":#"RUS",#"RW":#"RWA",
#"SA":#"SAU",#"SD":#"SDN",#"SN":#"SEN",#"SG":#"SGP",#"GS":#"SGS",#"SH":#"SHN",
#"SJ":#"SJM",#"SB":#"SLB",#"SL":#"SLE",#"SV":#"SLV",#"SM":#"SMR",#"SO":#"SOM",
#"PM":#"SPM",#"RS":#"SRB",#"SS":#"SSD",#"ST":#"STP",#"SR":#"SUR",#"SK":#"SVK",
#"SI":#"SVN",#"SE":#"SWE",#"SZ":#"SWZ",#"SX":#"SXM",#"SC":#"SYC",#"SY":#"SYR",
#"TC":#"TCA",#"TD":#"TCD",#"TG":#"TGO",#"TH":#"THA",#"TJ":#"TJK",#"TK":#"TKL",
#"TM":#"TKM",#"TL":#"TLS",#"TO":#"TON",#"TT":#"TTO",#"TN":#"TUN",#"TR":#"TUR",
#"TV":#"TUV",#"TW":#"TWN",#"TZ":#"TZA",#"UG":#"UGA",#"UA":#"UKR",#"UM":#"UMI",
#"UY":#"URY",#"US":#"USA",#"UZ":#"UZB",#"VA":#"VAT",#"VC":#"VCT",#"VE":#"VEN",
#"VG":#"VGB",#"VI":#"VIR",#"VN":#"VNM",#"VU":#"VUT",#"WF":#"WLF",#"WS":#"WSM",
#"XK":#"XKV",#"YE":#"YEM",#"ZA":#"ZAF",#"ZM":#"ZMB",#"ZW":#"ZWE",
//unknown status or codes, to be changed soon
#"DG":#"DGA" , //Diego Garcia
#"EA":#"EA_" , //Ceuta and Melilla
#"CP":#"CPT" , //Clipperton Island -> French Polynesia
#"IC":#"IC_" , //Kanarian Island
#"TA":#"TAA" , //டிரிஸ்டன் டா குன்ஹா , Tristan da Cunha -> St.Helena
};
this LUT makes it easy to lookup by 2 letter code and get the 3 letter codes. And in reality the list is much longer and matter of permanent changes.
and if you trust the sorting of Apples API you could just use a static NSArray instead of a plist or NSDictionary. The following prints it for use..
int i=1;
fprintf(stderr,"\nstatic NSString *isoA3accordingToAppleSorting[256] = {\n");
for (NSString *code in isoCountrys) {
if (i%20 == 19) fprintf(stderr,"\n");
NSString *iso3 = LUTisoA3counterpartCodes[code];
fprintf(stderr,"#\"%s\",",iso3.UTF8String);
i++;
}
fprintf(stderr,"};\n");
which looks like..
static NSString *countryCodeAsA3accordingToAppleSorting[256] = {
#"SHN",#"AND",#"ARE",#"AFG",#"ATG",#"AIA",#"ALB",#"ARM",#"AGO",#"ATA",#"ARG",#"ASM",#"AUT",#"AUS",#"ABW",#"ALA",#"AZE",#"BIH",
#"BRB",#"BGD",#"BEL",#"BFA",#"BGR",#"BHR",#"BDI",#"BEN",#"BLM",#"BMU",#"BRN",#"BOL",#"BES",#"BRA",#"BHS",#"BTN",#"BVT",#"BWA",#"BLR",#"BLZ",
#"CAN",#"CCK",#"COD",#"CAF",#"COG",#"CHE",#"CIV",#"COK",#"CHL",#"CMR",#"CHN",#"COL",#"CPT",#"CRI",#"CUB",#"CPV",#"CUW",#"CXR",#"CYP",#"CZE",
#"DEU",#"DGA",#"DJI",#"DNK",#"DMA",#"DOM",#"DZA",#"EA_",#"ECU",#"EST",#"EGY",#"ESH",#"ERI",#"ESP",#"ETH",#"FIN",#"FJI",#"FLK",#"FSM",#"FRO",
#"FRA",#"GAB",#"GBR",#"GRD",#"GEO",#"GUF",#"GGY",#"GHA",#"GIB",#"GRL",#"GMB",#"GIN",#"GLP",#"GNQ",#"GRC",#"SGS",#"GTM",#"GUM",#"GNB",#"GUY",
#"HKG",#"HMD",#"HND",#"HRV",#"HTI",#"HUN",#"IC_",#"IDN",#"IRL",#"ISR",#"IMN",#"IND",#"IOT",#"IRQ",#"IRN",#"ISL",#"ITA",#"JEY",#"JAM",#"JOR",
#"JPN",#"KEN",#"KGZ",#"KHM",#"KIR",#"COM",#"KNA",#"PRK",#"KOR",#"KWT",#"CYM",#"KAZ",#"LAO",#"LBN",#"LCA",#"LIE",#"LKA",#"LBR",#"LSO",#"LTU",
#"LUX",#"LVA",#"LBY",#"MAR",#"MCO",#"MDA",#"MNE",#"MAF",#"MDG",#"MHL",#"MKD",#"MLI",#"MMR",#"MNG",#"MAC",#"MNP",#"MTQ",#"MRT",#"MSR",#"MLT",
#"MUS",#"MDV",#"MWI",#"MEX",#"MYS",#"MOZ",#"NAM",#"NCL",#"NER",#"NFK",#"NGA",#"NIC",#"NLD",#"NOR",#"NPL",#"NRU",#"NIU",#"NZL",#"OMN",#"PAN",
#"PER",#"PYF",#"PNG",#"PHL",#"PAK",#"POL",#"SPM",#"PCN",#"PRI",#"PSE",#"PRT",#"PLW",#"PRY",#"QAT",#"REU",#"ROU",#"SRB",#"RUS",#"RWA",#"SAU",
#"SLB",#"SYC",#"SDN",#"SWE",#"SGP",#"SHN",#"SVN",#"SJM",#"SVK",#"SLE",#"SMR",#"SEN",#"SOM",#"SUR",#"SSD",#"STP",#"SLV",#"SXM",#"SYR",#"SWZ",
#"TAA",#"TCA",#"TCD",#"ATF",#"TGO",#"THA",#"TJK",#"TKL",#"TLS",#"TKM",#"TUN",#"TON",#"TUR",#"TTO",#"TUV",#"TWN",#"TZA",#"UKR",#"UGA",#"UMI",
#"USA",#"URY",#"UZB",#"VAT",#"VCT",#"VEN",#"VGB",#"VIR",#"VNM",#"VUT",#"WLF",#"WSM",#"XKV",#"YEM",#"MYT",#"ZAF",#"ZMB",#"ZWE",};
but then you have to find the index of your 2 letter code in apples ISOCountryCodes to look them up accordingly.
Reminder. The ISO 3166-1 alpha-3 explains only that it should have 3 letters, not which letter exactly
I have searched quite a bit without luck so far.
The Android Geocoder returns the android.location.Address object.
The city, as far as I understood, should be returned in getLocality().
It seems within USA this works well, outside not.
I am writing an international app and struggle to find a solution to find out the city of a geolocation.
Here the output from Czech Republic/Prague :
Address[addressLines=
[0:"Psohlavců 1764/2",
1:"147 00 Prague-Prague 4",
2:"Czech Republic"],
feature=2,
admin=Hlavní město Praha,
sub-admin=Prague,
locality=null,
thoroughfare=Psohlavců,
postalCode=147 00,
countryCode=CZ,
countryName=Czech Republic,
hasLatitude=true,
latitude=50.0276543,
hasLongitude=true,
longitude=14.4183926,
phone=null,
url=null,
extras=null]
locality is null, the city is within sub-admin !
The address itself is ok, so the geocoder server seems to know the city.
Here some ore random EU examples but locality works partly:
Address[addressLines=[0:"Nad lesem 440/34",1:"147 00 Prague-Prague 4",2:"Czech Republic"],feature=34,admin=Hlavní město Praha,sub-admin=Prague,locality=null,thoroughfare=Nad lesem,postalCode=147 00,countryCode=CZ,countryName=Czech Republic,hasLatitude=true,latitude=50.02424,hasLongitude=true,longitude=14.4117568,phone=null,url=null,extras=null]
Address[addressLines=[0:"Hauner Straße 4",1:"84431 Heldenstein",2:"Germany"],feature=4,admin=null,sub-admin=null,locality=Heldenstein,thoroughfare=Hauner Straße,postalCode=84431,countryCode=DE,countryName=Germany,hasLatitude=true,latitude=48.2540274,hasLongitude=true,longitude=12.3413535,phone=null,url=null,extras=null]
Address[addressLines=[0:"Igler Straße",1:"6020 Innsbruck",2:"Austria"],feature=Igler Straße,admin=Tyrol,sub-admin=Innsbruck,locality=Innsbruck,thoroughfare=Igler Straße,postalCode=6020,countryCode=AT,countryName=Austria,hasLatitude=true,latitude=47.2465698,hasLongitude=true,longitude=11.4054237,phone=null,url=null,extras=null]
Address[addressLines=[0:"Durnberg 24",1:"5724 Stuhlfelden",2:"Austria"],feature=24,admin=Salzburg,sub-admin=Zell am See District,locality=null,thoroughfare=Durnberg,postalCode=5724,countryCode=AT,countryName=Austria,hasLatitude=true,latitude=47.3233373,hasLongitude=true,longitude=12.4960482,phone=null,url=null,extras=null]
Address[addressLines=[0:"U Roháčových kasáren 14",1:"100 00 Prague 10",2:"Czech Republic"],feature=14,admin=Hlavní město Praha,sub-admin=Prague,locality=Prague 10,thoroughfare=U Roháčových kasáren,postalCode=null,countryCode=CZ,countryName=Czech Republic,hasLatitude=true,latitude=50.0704092,hasLongitude=true,longitude=14.4673473,phone=null,url=null,extras=null]
Maybe the fault is on me, but to me it seems like depending on the country and area the city will be found in different fields.
However, the address itself mostly seems to be good enough to send a postal letter.
Has someone written a clever function which tries to make more sense out of the Geocoder results ? It's a pity to see that Google has the information stored but does not provide it properly.
Going to close my question, solved it with a workaround.
Using the suggestion from dannyroa
String city="unknown";
if (address.getLocality() != null) city=address.getLocality();
else
if (address.getSubAdminArea() != null) city=address.getSubAdminArea();
This could be further extended by getting the city information out of the second address line.
removing the postal code and taking the remainder, but this information is not unique within a city and could change depending on the district/zone.