Использование NSScanner для сканирования многострочного текстового файла

У меня есть опыт разработки на Java и Android, и сейчас я пытаюсь изучить разработку на Objective-C и iPhone/iPad. Чтобы помочь себе в обучении, я переписываю приложение, которое я сделал для Android, на iPhone.

Конкретная проблема, с которой я столкнулся, связана с использованием класса NSScanner. В моем приложении для Android я читаю текстовый файл (с несколькими строками) и создаю объекты-члены, которые загружаются в массив. У каждого участника есть общая контактная информация: имя, фамилия, номер телефона, электронная почта, класс залога и специальность. Этот текстовый файл был написан мной, поэтому я знаю точное форматирование. Ниже приведен пример одной строки в текстовом файле.

Fawzy   Jake    8144425471  [email protected] Beta    Criminal Justice & Psych Minor

В Java/android я смог загрузить желаемые результаты, используя несколько scan.Next(), а затем scan.nextLine() для основного. Может ли кто-нибудь помочь указать мне правильное направление, как использовать NSScanner/objective-c для выполнения аналогичной операции? В частности, я хотел бы знать, как правильно сканировать текстовый файл/строку, а затем создавать свой объект-член с информацией, которую я получил из строки.

Ниже приведен пример моего кода, над которым я работал, но у меня возникли проблемы с логическим выводом того, что я хочу сделать, в синтаксис, поскольку я не знаком с target-c.

- (NSString *)loadFileToString{
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"akpsi_contact_list"
                                                     ofType:@"txt"];
NSError *error = nil;
NSString *fileContent = [NSString stringWithContentsOfFile:filePath
                                                  encoding:NSUTF8StringEncoding
                                                     error:&error];
if(error)
{
    NSLog(@"ERROR while loading from file: %@", error);
}
return fileContent;
}

-(void)readFileString{
NSScanner *scanner = [NSScanner scannerWithString: self.loadFileToString];
while ([scanner isAtEnd] == NO) {

    //member object
    AKPsiMember *member;

    //temporary variables
    NSString *thisFirstName;
    NSString *thisLastName;
    NSString *thisPhoneNum;
    NSString *thisEmail;
    NSString *thisPledge;
    NSString *thisMajor;

    //scan one line, save 
    [scanner scanUpToString:@" " intoString:&thisFirstName];
    [scanner scanUpToString:@" " intoString:&thisLastName];
    [scanner scanUpToString:@" " intoString:&thisPhoneNum];
    [scanner scanUpToString:@" " intoString:&thisEmail];
    [scanner scanUpToString:@" " intoString:&thisPledge];
    [scanner scanUpToString:@" " intoString:&thisMajor];
    //build member object with temporary variables
    // implementation must continue to next line...
}    

}

Также мой объект-член/класс

.h

@interface AKPsiMember : NSObject{
NSString *firstName;
NSString *lastName;
NSString *emailAddress;
NSString *pledgeClass;
NSString *major;
NSString *phoneNum;


}

@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSString *emailAddress;
@property (nonatomic, strong) NSString *pledgeClass;
@property (nonatomic, strong) NSString *major;
@property (nonatomic, strong) NSString *phoneNum;


@end

И мой .м

@implementation AKPsiMember

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;
@synthesize phoneNum = _phoneNum;
@synthesize emailAddress = _emailAddress;
@synthesize pledgeClass = _pledgeClass;
@synthesize major = _major;

- (NSString *)phoneNum:(NSNumber *)num
{
if(num == 0)
{
    NSString *temp1 = [self.phoneNum substringWithRange:NSMakeRange(0, 3)];
    NSString *temp2 = [self.phoneNum substringWithRange:NSMakeRange(3, 6)];
    NSString *temp3 = [self.phoneNum substringWithRange:NSMakeRange(6, 9)];

    NSString *formatNum = [NSString stringWithFormat: @"(%@) %@-%@", temp1, temp2, temp3];
    return formatNum;
}
else{
    return self.phoneNum;
}
}

@end

person bmjohns    schedule 24.06.2013    source источник


Ответы (1)


После того, как вы просмотрели все свои поля, вы должны отсканировать символ новой строки, чтобы перейти к следующей строке:

NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisFirstName];
[scanner scanCharactersFromSet:whitespace intoString:nil];        
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisLastName];
[scanner scanCharactersFromSet:whitespace intoString:nil];
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisPhoneNum];
[scanner scanCharactersFromSet:whitespace intoString:nil];
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisEmail];
[scanner scanCharactersFromSet:whitespace intoString:nil];
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisPledge];
[scanner scanCharactersFromSet:whitespace intoString:nil];

NSCharacterSet *newLineCharacterSet = [NSCharacterSet newlineCharacterSet];
[scanner scanUpToCharactersFromSet:newLineCharacterSet intoString:&thisMajor];
[scanner scanCharactersFromSet:newLineCharacterSet intoString:nil];

Создайте NSMutableArray перед циклом.

NSMutableArray *members = [NSMutableArray array];

Установите значения внутри цикла и добавьте свой объект в массив членов.

AKPsiMember *member = [[AKPsiMember alloc] init];
member.firstName = thisFirstName;
// ... set other properties
[members addObject:member];

Этот код сломается, если между первыми полями вашего набора данных будут пробелы. Очевидно, что это можно разбить на методы, и результаты должны быть проверены.

person Karl    schedule 24.06.2013
comment
Хорошо, большое спасибо за этот ответ! Мой последний вопрос заключается в том, как мне создать/установить поля, которые я теперь получил, для моего созданного объекта AKPsiMember *member. Обычно в Java я просто помещал AKPsiMember member = new member(thisFirstName, thisLastName, ect...), а затем добавлял этого члена в свой массив. - person bmjohns; 25.06.2013
comment
Я добавил некоторый код для установки свойств и добавления этого объекта в массив. - person Karl; 25.06.2013
comment
Спасибо за всю помощь, сэр! - person bmjohns; 25.06.2013
comment
Извините, похоже, у меня возникла проблема с настройкой размещения объектов в моем массиве, так как объекты строятся правильно, но массив пуст, когда я иду на него ссылаться, например, чтобы заполнить табличное представление. Не могли бы вы взглянуть на мой класс AKPsiMember выше? Если AKPsiMember состоит из имени, фамилии и т. д. Правильно ли я определил его в своих файлах .m и .h? Кроме того, если это имеет значение, мои изменяемые массивы определены в моем файле .h для класса, в котором находится сканер строк, а не в фактическом методе. - person bmjohns; 25.06.2013
comment
Вы уверены, что ваш массив инициализирован? Просто добавьте точку останова в точку, где вы добавляете объект, и убедитесь, что она не равна нулю. - person Karl; 25.06.2013
comment
Yikes, глупый ход с моей стороны. Мой массив теперь правильно заполняется. У меня последний вопрос, если вы не возражаете. При запуске отладчика я заметил, что мой объект-член заполнен дубликатами моих переменных NSString. Так как есть firstName, заполненный нулевым значением, а также _firstName, заполненный соответствующей строкой. Это нормально или что-то не так? - person bmjohns; 25.06.2013
comment
В заголовочном файле вы объявляете такие свойства, как firstName и ivar с тем же именем. В реализации вы синтезируете свое свойство с firstName = _firstName, которое сообщает компилятору создать геттер и набор, который будет поддерживаться ivar с именем _firstName. Поэтому ваш другой ивар больше не используется. Вы должны избавиться от ivars в файлах заголовков и @synthesize в вашем файле реализации, потому что Xcode сделает это автоматически за вас. - person Karl; 25.06.2013