38

I'm looking for an easy to use CSV parser for Objective-C to use on the iPhone. Where can I find one?

I'm also looking for other parsers such as JSON, so maybe there is a conversion library somewhere.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Toby Allen
  • 10,997
  • 11
  • 73
  • 124

8 Answers8

51

I finally got around to cleaning up a parser I've had in my code folder and posted it on Github: http://github.com/davedelong/CHCSVParser

It's quite thorough. It handles all sorts of escaping schemes, newlines in fields, comments, etc. It also uses intelligent file loading, which means you can safely parse huge files in constrained memory conditions.

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • I have checked the Github Link that you have given as such it looks fine but when I tried testing it in iPhone simulator then it does not seem to work. Simulator does not open. Also the base SDK has been set to Mac OS X 10.5. So will this not work for iPhone? What should be done? Thanks. :) – Parth Bhatt Dec 23 '10 at 09:12
  • 1
    @PARTH there's a list of files in the general use section of the readme. Copy those into your project and `#import "CHCSV.h"` – Dave DeLong Dec 23 '10 at 15:33
  • Thanks Dave for answering my silly question :) Also then I suppose we have to just use arrayWithContentsofCSVFile: method. right? – Parth Bhatt Dec 24 '10 at 03:35
  • @PARTH that's definitely one of the easiest ways to do it! You can also go the whole parser-with-a-delegate route if you want. – Dave DeLong Dec 24 '10 at 03:36
19

Here's a simple category on NSString to parse a CSV string that has commas embedded inside quote blocks.

#import "NSString+CSV.h"

@implementation NSString (CSV)

- (NSArray *)componentsSeparatedByComma
{
    BOOL insideQuote = NO;
    NSMutableArray *results = [[NSMutableArray alloc] init];
    NSMutableArray *tmp = [[NSMutableArray alloc] init];

    for (NSString *s in [self componentsSeparatedByString:@","]) {
        if ([s rangeOfString:@"\""].location == NSNotFound) {
            if (insideQuote) {
                [tmp addObject:s];
            } else {
                [results addObject:s];
            }
        } else {
            if (insideQuote) {
                insideQuote = NO;
                [tmp addObject:s];
                [results addObject:[tmp componentsJoinedByString:@","]];
                tmp = nil;
                tmp = [[NSMutableArray alloc] init];
            } else {
                insideQuote = YES;
                [tmp addObject:s];
            }
        }
    }

    return results;
}

@end

This assumes you've read your CSV file into an array already:

myArray = [myData componentsSeparatedByString:@"\n"];

The code doesn't account for escaped quotes, but it could easily be extended to.

gose
  • 290
  • 3
  • 7
8

Quick way to do this:

NSString *dataStr = [NSString stringWithContentsOfFile:@"example.csv" encoding:NSUTF8StringEncoding error:nil];
NSArray *array = [dataStr componentsSeparatedByString: @","];

xmr
  • 635
  • 8
  • 9
5

Well, above simple solutions doesn't take into account multiple records. Use the following code reading a default excel CSV using ASCI 13 as line end marker:

NSString *content =  [NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:nil];
NSArray *contentArray = [content componentsSeparatedByString:@"\r"]; // CSV ends with ACSI 13 CR (if stored on a Mac Excel 2008)

for (NSString *item in contentArray) {
    NSArray *itemArray = [item componentsSeparatedByString:@";"];
    // log first item
    NSLog(@"%@",[itemArray objectAtIndex:0]);
}
JeanNicolas
  • 357
  • 3
  • 9
  • you have to consider that while this might work for simple files, it will not work in many scenarios. There are cases where you can escape the commas, or when you put a value inside quotations. componentsSeparatedByString will not catch any of these. There are also scenarios when a cell value can contain a new-line, so in these scenarios, your content array wouldn't be accurate either. This is why other people are recommending using libraries, such as CHCSV Parser. These are built to handle all these scenarios. – Rob Jun 14 '14 at 20:24
3

I wrote a dead-simple (although not fully-featured) CSV parser for a project I was working on: CSVFile.h and CSVFile.m. Feel free to grab it -- the code is available under the GPLv3 (unfortunately, it was a requirement for the project I was working on) but I'd be happy to license it to you under an MIT license or another license.

mipadi
  • 398,885
  • 90
  • 523
  • 479
1

This seems to be the most comprehensive that I've found so far.

http://www.macresearch.org/cocoa-scientists-part-xxvi-parsing-csv-data

As a side note, you'd think most major languages (Delphi, C#, Objective-c, php etc) would have a library available with a full implementation of this basic data interchange format.

I know json is cool and XML is reliable but neither are available as a save option from most applications saving table data. CSV still is.

Toby Allen
  • 10,997
  • 11
  • 73
  • 124
0

I've found ParseKit few weeks ago But IMHO for most cases -[NSString componentsSeparatedByString:] method and NSScanner are more than enough and quite easy to use.

OgreSwamp
  • 4,602
  • 4
  • 33
  • 54
-2

As xmr said above: It's possible in Objective C to convert an NSString csv into 'components separated by string' array.

    NSArray* items;
    items=[bufferString componentsSeparatedByString:@","];       

In case you are interested in csv export having arrived at this thread - as I did - here is an extract of how I exported a csv file.

    NSString* fileName    = @"Level";
    fileName = [fileName stringByAppendingString:levelNumberBeingEdited];
    fileName = [fileName stringByAppendingString:@".txt"];
    NSString* bufferString=@"";  

Buffer String is populated by looping through each data item (not shown) and inserting a comma between each. Finally it's exported.

    NSString* homeDir = NSHomeDirectory();
    NSString* fullPath = [homeDir stringByAppendingPathComponent:fileName];
    NSError* error = nil;
    [bufferString writeToFile:fullPath atomically:NO encoding:NSASCIIStringEncoding error:&error];
  • 7
    -1 whatever this is, it's not an answer on how to parse CSV files. Flagged. – Dave DeLong Nov 12 '11 at 01:47
  • 1
    I have edited my answer. I was led to this thread and xmr solved my issue. I thought it would be useful to show how the actual csv text file fits into his solution. – Barnaby Byrne Nov 25 '11 at 00:41