Как использовать класс CHCSVParser - PullRequest
13 голосов
/ 24 сентября 2010

Я играю с превосходным CHCSVParser Дэйва ДеЛонга для Objective-C с очень длинным файлом .CSV и столкнулся с некоторыми проблемами при его использовании. Я бы использовал метод arrayWithContentsOfCSVFile, но я запускаю код на iPhone и анализ всего файла в памяти займет больше памяти, чем доступно.

В моем коде ниже парсер открывает документ и прекрасно вызывает методы делегата, но где в делегате я останавливаюсь после каждой строки и получаю доступ к данным (чтобы создать и сохранить объект Core Data в хранилище данных)? Я предполагаю, что это будет в - (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber, но как мне получить NSArray (или что-то еще) из данных парсера, когда это будет сделано со строкой?

Вот мой код:

//
// The code from a method in my view controller:
//
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSError *err = nil;
NSArray *fileList = [manager contentsOfDirectoryAtPath:documentsDirectory error:&err];
NSString *fileName = [fileList objectAtIndex:1];
NSURL *inputFileURL = [NSURL fileURLWithPath: [documentsDirectory stringByAppendingPathComponent:fileName]];


NSStringEncoding encoding = 0;
CHCSVParser *p = [[CHCSVParser alloc] initWithContentsOfCSVFile:[inputFileURL path] usedEncoding:&encoding error:nil];
[p setParserDelegate:self];
[p parse];
[p release];

...

#pragma mark -
#pragma mark CHCSVParserDelegate methods

- (void) parser:(CHCSVParser *)parser didStartDocument:(NSString *)csvFile {
    NSLog(@"Parser started!");
}

- (void) parser:(CHCSVParser *)parser didStartLine:(NSUInteger)lineNumber {
    //NSLog(@"Parser started line: %i", lineNumber);
}

- (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber {
    NSLog(@"Parser ended line: %i", lineNumber);
}

- (void) parser:(CHCSVParser *)parser didReadField:(NSString *)field {
    //NSLog(@"Parser didReadField: %@", field);
}

- (void) parser:(CHCSVParser *)parser didEndDocument:(NSString *)csvFile {
    NSLog(@"Parser ended document: %@", csvFile);
}

- (void) parser:(CHCSVParser *)parser didFailWithError:(NSError *)error {
    NSLog(@"Parser failed with error: %@ %@", [error localizedDescription], [error userInfo]);
}

Спасибо!

Ответы [ 2 ]

17 голосов
/ 24 сентября 2010

Я рад видеть, что мой код оказывается полезным! :)

CHCSVParser по поведению похож на NSXMLParser в том, что каждый раз, когда он находит что-то интересное, он сообщит вам об этом через один из обратных вызовов делегата. Однако, если вы решите игнорировать данные, которые он вам дает при обратном вызове, то он исчезнет. Эти парсеры (CHCSVParser и NSXMLParser) довольно глупы. Они просто знают формат материала, который они пытаются проанализировать, но на самом деле ничего особенного не делают.

Таким образом, ответ, в двух словах, таков: «Вы должны спасти его сами». Если вы посмотрите на код для категории NSArray, вы увидите в файле .m, что он использует простой подкласс NSObject в качестве делегата синтаксического анализатора , и этот подкласс является тем, что объединяет поля в массив, а затем добавив этот массив в общий массив. Вам нужно будет сделать что-то подобное.

Пример делегата:

@interface CSVParserDelegate : NSObject <CHCSVParserDelegate> {
  NSMutableArray * currentRow;
}
@end

@implementation CSVParserDelegate

- (void) parser:(CHCSVParser *)parser didStartLine:(NSUInteger)lineNumber {
  currentRow = [[NSMutableArray alloc] init];
}
- (void) parser:(CHCSVParser *)parser didReadField:(NSString *)field {
  [currentRow addObject:field];
}
- (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber {
  NSLog(@"finished line! %@", currentRow);
  [self doSomethingWithLine:currentRow];
  [currentRow release], currentRow = nil;
}
@end

Тем не менее, я мог бы быть убежден, что нужно изменить поведение синтаксического анализатора для агрегирования самой строки, но если я пойду по этому пути, почему бы просто не собрать синтаксический анализатор для всего файла? (Ответ: не должно)

1 голос
/ 29 мая 2014

Я пытался использовать это сегодня, основываясь на превосходном ответе и коде @ DaveDeLong, но я думаю, что программное обеспечение было пересмотрено с момента его ответа (2010). На момент написания я обнаружил, что должен был использовать это:

@interface CSVParserDelegate : NSObject <CHCSVParserDelegate> {
  NSMutableArray * currentRow;
}
@end

@implementation CSVParserDelegate

- (void) parser:(CHCSVParser *)parser didBeginLine:(NSUInteger)lineNumber {
  currentRow = [[NSMutableArray alloc] init];
}
- (void) parser:(CHCSVParser *)parser didReadField:(NSString *)field atIndex:(NSInteger)fieldIndex {
  [currentRow addObject:field];
}
- (void) parser:(CHCSVParser *)parser didEndLine:(NSUInteger)lineNumber {
  NSLog(@"finished line! %@", currentRow);
  [self doSomethingWithLine:currentRow];
  [currentRow release], currentRow = nil;
}
@end

т.е. parser:didStartLine:lineNumber: стало parser:didBeginLine:lineNumber:, а parser:didReadField: стало parser:didReadField:atIndex:.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...