Мне очень хочется добавить RegexKit (или мою собственную оболочку libpcre) в мой проект, чтобы сделать это, но прежде чем я это сделаю, я хочу узнать, как разработчикам Cocoa удается выполнить половину этих базовых вещей без действительно сложного код или без связи с RegexKit или другой библиотекой регулярных выражений.
Мне кажется, что Какао не включает никаких функций сопоставления регулярных выражений. Я так привык использовать регулярные выражения для всех видов вещей, что я потерял без них. Я могу делать то, что мне нужно без них, но код будет довольно запутанным. Итак, разработчики Какао, я спрашиваю вас, что такое «способ Какао», чтобы сделать это ...
Эта проблема - повседневная проблема в программировании, насколько я понимаю. Какао должен иметь способы сделать это с помощью встроенных функций. Обратите внимание, что положение элементов, которые я хочу сопоставить, изменяется, и иногда присутствуют «кавычки». Пробелы являются переменными.
Взять следующие строки:
Content-Type: application/xml; charset=utf-8
Content-Type: text/html; charset="iso-8859-1"
Content-Type: text/plain;
charset=us-ascii
Content-Type: text/plain; name="example.txt"; charset=utf-8
Из всех этих строк, как бы вы определили тип MIME (например, text / plain) и кодировку (например, utf-8), используя только встроенные классы Какао?
Я бы закончил тем, что выполнил серию вызовов -rangeOfString:
и подстрок, с условными проверками для обработки необязательных кавычек и т. Д. Есть ли способ сделать это с NSScanner? Класс NSScanner, кажется, имеет довольно наивный API для меня.
Что-то вроде C's sscanf()
, которое работает для объектов NSString, было бы идеальным выбором. Большинство моих потребностей в разборе строк просты, такие как этот пример, так что, может быть, регулярные выражения, хотя я к ним привык, излишни?
РЕДАКТИРОВАТЬ | Код немного затянут, но получается, что с NSScanner довольно легко работать. Он в основном идет по твоей струне, делая то, что ты говоришь. Самая раздражающая часть создания NSCharacterSet
необходимых экземпляров.
- (void)testNSScannerUseCase {
NSString *testString = @"Content-type: application/xml; name=\"test\";\n charset=\"utf-8\"";
unsigned int a = 'a', zero = '0';
// There's probably a quicker way than to make these character sets this way
NSMutableCharacterSet *alphaNumSet = [NSMutableCharacterSet characterSetWithRange:NSMakeRange(a, 26)];
[alphaNumSet addCharactersInRange:NSMakeRange(zero, 10)];
NSMutableCharacterSet *mimeTypeSet = [NSMutableCharacterSet characterSetWithCharactersInString:@"/-"];
[mimeTypeSet formUnionWithCharacterSet:alphaNumSet];
NSMutableCharacterSet *charsetSet = [NSMutableCharacterSet characterSetWithCharactersInString:@"-"];
[charsetSet formUnionWithCharacterSet:alphaNumSet];
// Initialize a case-insensitive scanner
NSScanner *scanner = [NSScanner scannerWithString:testString];
[scanner setCaseSensitive:NO];
// Prepare to capture mime-type
NSString *mimeType = nil;
// Skip past the Content-Type: section
if ([scanner scanUpToString:@":" intoString:NULL] && [scanner scanString:@":" intoString:NULL]) {
[scanner scanCharactersFromSet:mimeTypeSet intoString:&mimeType];
}
GHAssertEqualStrings(@"application/xml", mimeType, @"Mime-type should be application/xml");
// Prepare to look for the charset attribute
NSString *charset = nil;
// Ignore quotes as well as whitespace
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"\r\n\t \""]];
// Skip past the charset attribute declaration
if ([scanner scanUpToString:@"charset=" intoString:NULL]
&& [scanner scanString:@"charset=" intoString:NULL]) {
[scanner scanCharactersFromSet:charsetSet intoString:&charset];
}
GHAssertEqualStrings(@"utf-8", charset, @"Charset should be utf-8");
}
Это можно сделать немного умнее, используя цикл while, читающий до ";" затем проверим, проверяет ли это атрибут.
Осмелюсь сказать, что это тесты быстрее, чем использование регулярных выражений, и что мой довольно длинный код может быть реорганизован до чего-то гораздо меньшего.