0

I created an array called NSArray citiesList from a text file separating each object by the "," at the end of the line. Here is what the raw data looks like from the text file.

City:San Jose|County:Santa Clara|Pop:945942,
City:San Francisco|County:San Francisco|Pop:805235,
City:Oakland|County:Alameda|Pop:390724,
City:Fremont|County:Alameda|Pop:214089,
City:Santa Rosa|County:Sonoma|Pop:167815,

The citiesList array is fine (I can see count the objects, see the data, etc.) Now I want to parse out the city and Pop: in each of the array objects. I assume that you create a for loop to run through the objects, so if I wanted to create a mutable array called cityNames to populate just the city names into this array I would use this kind of for loop:

SMutableArray *cityNames = [NSMutableArray array];
    for (NSString *i in citiesList) {
        [cityNames addObject:[???]];
    }

My question is what is what query should I use to find just the City: San Francisco from the objects in my array?

1
  • 1
    I see that you are using an array for this data. Have you considered using NSDictionary? That way you can store each object as cityData object and use key value pairs to extract the data. Commented Aug 7, 2013 at 21:54

4 Answers 4

2

You can continue to use componentsSeparatedByString to divide up the sections and key/value pairs. Or you can use an NSScanner to read through the string parsing out the key/value pairs. You could use rangeOfString to find the "|" and then extract a range. So many options.

Sign up to request clarification or add additional context in comments.

Comments

2

Many good suggestions in the answers here in case you really want to construct an algorithm to parse the string.

As an alternative to that, you can also look at it as a problem of declaring the structure of the data and then just have the system do the parsing. For a case like yours, regular expressions will do that nicely. Whether you prefer to do it one way or the other is largely a question of taste and coding standards.

In your specific case (if the city name is all you need to extract from the string), then also notice that there is a bit of a shortcut available that will turn it into a one-line solution: Match the whole string, define a single capture group and substitute that one to make a new string:

NSString *city = [i stringByReplacingOccurrencesOfString: @".*City:(.*?)\\|.*"
                                              withString: @"$1"
                                                 options: NSRegularExpressionSearch
                                                   range: NSMakeRange(0, row.length)];

The variable i is the same that you have defined in your for-loop, i.e. a string containing a string representing a line in your input file:

City:San Jose|County:Santa Clara|Pop:945942,

I have added the initial .* to make the pattern robust to future new fields added to the rows. You can remove it if you don't like it.

The $1 in the substitution string represents the first capture group, i.e. the parenthesis in the regex pattern. In this specific case, the substring containing the city name. Had there been more capture groups, they would have been named $2-$9. You can check the documentation on NSRegularExpression and NSString if you want to know more.

Regular expressions are a topic all of their own, not confined to the Cocoa, although all platforms use regex implementations with their own idiosyncrasies.

1 Comment

Very useful approach. Thanks. To confirm / clarify things is i the full dataset that I am passing into it? Is the $1 replacement a regular expression - what specifically does that do?
1

You want to use componentsSeparatedByString: as below. (These lines do no error checking)

NSArray *fields = [i componentsSeparatedByString:@"|"];
NSString *city = [[[fields objectAtIndex:0] componentsSeparatedByString:@":"] objectAtIndex:1];
NSString *county = [[[fields objectAtIndex:1] componentsSeparatedByString:@":"] objectAtIndex:1];

If you can drop the keys, and a couple delimiters like this:

San Jose|Santa Clara|945942
San Francisco|San Francisco|805235
Oakland|Alameda|390724
Fremont|Alameda|214089
Santa Rosa|Sonoma|167815

Then you can simplify the code (still no error checking):

NSArray *fields = [i componentsSeparatedByString:@"|"];
NSString *city = [fields objectAtIndex:0];
NSString *county = [fields objectAtIndex:1];

Comments

1
for (NSString *i in citiesList) {
  // Divide each city into an array, where object 0 is the name, 1 is county, 2 is pop
  NSArray *stringComponents = [i componentsSeparatedByString:@"|"];
  // Remove "City:" from string and add the city name to the array
  NSString *cityName = [[stringComponents objectAtIndex:0] stringByReplacingCharactersInRange:NSMakeRange(0, 5) withString:@""];
  [cityNames addObject:cityName];
}

2 Comments

Just to confirm I get this... the 'stringByReplacingCharactersInRange:NSMakeRange(0, 5) withString:@""' takes the first five characters "City:" and replaces that with the city name e.g. "San Jose"?
It replaces the first five chars with nothing, effectively removing the first five chars.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.