Skip to content

Instantly share code, notes, and snippets.

@BlackFrog1
Created April 15, 2011 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BlackFrog1/921481 to your computer and use it in GitHub Desktop.
Save BlackFrog1/921481 to your computer and use it in GitHub Desktop.
Class to load GeoName raw text file (draft)
//
// BFGeoname.h
// Rooster
//
// Created by Collin Bennett on 3/20/11.
//
// This work is licensed under a Creative Commons Attribution 3.0 License,
// see http://creativecommons.org/licenses/by/3.0/
// The Data is provided "as is" without warranty or any representation of accuracy, timeliness or completeness.
//
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
@interface BFGeoname : NSObject {
@private
// The main 'geoname' table has the following fields
NSInteger geonameid_; // integer id of record in geonames database
NSString *name_; // name of geographical point (utf8) varchar(200)
NSString *asciiname_; // name of geographical point in plain ascii characters, varchar(200)
NSString *alternatenames_; // alternatenames, comma separated varchar(5000)
// latitude // latitude in decimal degrees (wgs84)
// longitude // longitude in decimal degrees (wgs84)
CLLocationCoordinate2D coordinate_;
// feature class // see http////www.geonames.org/export/codes.html, char(1)
// feature code // see http////www.geonames.org/export/codes.html, varchar(10)
// country code // ISO-3166 2-letter country code, 2 characters
// cc2 // alternate country codes, comma separated, ISO-3166 2-letter country code, 60 characters
// admin1 code // fipscode (subject to change to iso code), see exceptions below, see file admin1Codes.txt for display names of this code; varchar(20)
// admin2 code // code for the second administrative division, a county in the US, see file admin2Codes.txt; varchar(80)
// admin3 code // code for third level administrative division, varchar(20)
// admin4 code // code for fourth level administrative division, varchar(20)
// population // bigint (8 byte int)
// elevation // in meters, integer
// gtopo30 // average elevation of 30'x30' (ca 900mx900m) area in meters, integer
// timezone // the timezone id (see file timeZone.txt)
// modification date // date of last modification in yyyy-MM-dd format
}
@property (readonly, nonatomic) NSInteger geoId;
@property (readonly, nonatomic) NSString *name;
@property (readonly, nonatomic) NSString *asciiName;
@property (readonly, nonatomic) NSArray *alternateNames;
@property (readonly, nonatomic) CLLocationCoordinate2D coordinate;
- (id)initWithRawData:(NSString *)data;
+ (BFGeoname *)rawData:(NSString *)data;
@end
//
// BFGeoname.m
//
// Created by Collin Bennett on 3/20/11.
//
// This work is licensed under a Creative Commons Attribution 3.0 License,
// see http://creativecommons.org/licenses/by/3.0/
// The Data is provided "as is" without warranty or any representation of accuracy, timeliness or completeness.
//
#import "BFGeoname.h"
@interface NSArray (FieldUtility)
- (NSString *)stringAtIndex:(NSUInteger)index;
@end
@interface BFGeoname (PrivateMethods)
- (BOOL)assignFields:(NSArray *)fields;
@end
@implementation BFGeoname
@synthesize geoId = geonameid_;
@synthesize name = name_, asciiName = asciiname_;
@synthesize alternateNames;
@synthesize coordinate = coordinate_;
+ (BFGeoname *)rawData:(NSString *)data {
BFGeoname *geo = [[BFGeoname alloc] initWithRawData:data];
return [geo autorelease];
}
- (id)initWithRawData:(NSString *)data {
self = [super init];
if (self) {
NSArray *fields;
BOOL validData = YES;
// check we have data before we continue
if (data == nil)
validData = NO;
// parse the data into an array
if (validData) {
fields = [data componentsSeparatedByString:@"\t"];
// I consider the data valid if I have at least 6 fields
// which are the fields up the location
if ([fields count] < 6)
validData = NO;
else
validData = [self assignFields:fields];
}
// If we have incomplete data, self destory and return nil
if (!validData) {
[self release];
return nil;
}
}
return self;
}
- (void)dealloc {
[name_ release];
[super dealloc];
}
- (BOOL)assignFields:(NSArray *)fields {
// The main 'geoname' table has the following fields
NSLog(@"+++++++++++++++++++++++++");
int arrayCount = [fields count];
for (int x = 0; x < arrayCount; x++) {
NSString *s = [fields stringAtIndex:x];
NSLog(@"%d: %@ (%d)", x, s, [s length]);
}
// integer id of record in geonames database
geonameid_ = [[fields stringAtIndex:0] intValue];
// name of geographical point (utf8) varchar(200)
name_ = [[fields stringAtIndex:1] retain];
// name of geographical point in plain ascii characters, varchar(200)
asciiname_ = [[fields stringAtIndex:2] retain];
// alternatenames, comma separated varchar(5000)
alternatenames_ = [[fields stringAtIndex:3] retain];
// latitude in decimal degrees (wgs84)
coordinate_.latitude = [[fields stringAtIndex:4] doubleValue];
// longitude in decimal degrees (wgs84)
coordinate_.longitude = [[fields stringAtIndex:5] doubleValue];
// feature class : see http://www.geonames.org/export/codes.html, char(1)
// feature code : see http://www.geonames.org/export/codes.html, varchar(10)
// country code : ISO-3166 2-letter country code, 2 characters
// cc2 : alternate country codes, comma separated, ISO-3166 2-letter country code, 60 characters
// admin1 code : fipscode (subject to change to iso code), see exceptions below, see file admin1Codes.txt for display names of this code; varchar(20)
// admin2 code : code for the second administrative division, a county in the US, see file admin2Codes.txt; varchar(80)
// admin3 code : code for third level administrative division, varchar(20)
// admin4 code : code for fourth level administrative division, varchar(20)
// population : bigint (8 byte int)
// elevation : in meters, integer
// gtopo30 : average elevation of 30'x30' (ca 900mx900m) area in meters, integer
// timezone : the timezone id (see file timeZone.txt)
// modification date : date of last modification in yyyy-MM-dd format
return YES;
}
- (NSArray *)alternateNames {
if (alternatenames_ == nil)
return nil;
return [alternatenames_ componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];
}
@end
@implementation NSArray (FieldUtility)
- (NSString *)stringAtIndex:(NSUInteger)index {
NSString *s = (NSString *)[self objectAtIndex:index];
if ([s length] == 0)
return nil;
return s;
}
@end
// example load method
- (NSArray *)loadData {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"cities1000" ofType:@"txt"];
// Load the contents of the file into memory
NSError *err = nil;
NSString *contents = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&err];
if (err != nil) {
// Something went wrong
NSLog(@"Error reading failed banks text file: %@", [err localizedDescription]);
return nil;
}
// convert the content into an array of each line
NSArray *lines = [contents componentsSeparatedByString:@"\n"];
//NSArray *lines = [contents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
return lines;
}
// sample code to parse a line of data
// I would use a loop and load the information in Core Data
NSArray *cities = [self loadData];
NSLog(@"City count: %d", [cities count]);
BFGeoname *g = [BFGeoname rawData:[cities objectAtIndex:0]];
NSLog(@"Name: %@", [g name]);
NSString *locationText = NSLocalizedString(@"TestKey", @"This is where I get my location text");
NSLog(@"%@: %f, %f", locationText, [g coordinate].latitude, [g coordinate].longitude);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment