2010-09-24 4 views

ответ

3

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

Способ загрузки файлов с помощью NSFileHandle. Что-то вроде этого:

NSFileHandle * file = [NSFileHandle fileHandleForReadingAtPath:pathToFile]; 
NSUInteger chunkSize = 1024; 
NSData * chunk = [file readDataOfLength:chunkSize]; 
NSUInteger numberOfNewlines = 0; 
while ([chunk length] > 0) { 
    const unichar * bytes = (const unichar *)[chunk bytes]; 
    for (int index = 0; index < [chunk length]; ++index) { 
    unichar character = (unichar)bytes[index]; 
    if ([[NSCharacterSet newlineCharacterSet] characterIsMember:character]) { 
     numberOfNewlines++; 
    } 
    } 
    chunk = [file readDataOfLength:chunkSize]; 
} 
+0

Хороший! На самом деле я просто упустил из виду, откуда Фред получал струну. Шахта универсальна для подсчета подстроки, но, как ответ на самый вопрос о Фреде, ваш выбор - лучший выбор.Компилятор выдает ошибку на «(unichar) байтах [index];» для меня, хотя (ошибка: «Значение Void не игнорируется, как должно быть»), и по какой-то неизвестной и жуткой причине количество чисел меняется для меня при каждом прогоне и слишком низкое (по величине). O_o – Regexident

+0

Btw, поскольку [fileHandle readDataOfLength: length] должен возвращать автореализованные NSData (документы не содержат исключения, поэтому я должен предположить, что это происходит, по соглашению об именах), вы в конечном итоге получите столько же данных в памяти, учитывая, что в вашем коде на данный момент нет NSAutoreleasePool внутри цикла while. поправьте меня если я ошибаюсь. – Regexident

+0

@Regexident WRT ошибка: индексирование в 'void *' приводит к 'void', поэтому ответ будет заключаться в использовании другого типа массива (отредактированный ответ). Память WRT: да, вероятно, вы должны создавать и сливать пулы автозапуска, чтобы сохранить использование памяти. –

3

Это должно вас происходит:

NSString *fileContents = [NSString stringWithContentsOfFile:file encoding:encoding error:&error]; 
NSUInteger newlineCount = [fileContents numberOfOccurrencesOfString:@"\n"]; 

@interface NSString() 

- (NSUInteger)numberOfOccurrencesOfString:(NSString *)aString; 
- (NSUInteger)numberOfOccurrencesOfChar:(char)aChar; 

@end 

@implementation NSString() 

- (NSUInteger)numberOfOccurrencesOfString:(NSString *)aString { 
    NSRange range = [self rangeOfString:aString]; 
    NSUInteger length = [self length]; 
    NSUInteger count = 0; 
    while (range.location != NSNotFound) { 
     range = [self rangeOfString:aString options:0 range:NSMakeRange(range.location + range.length, length - range.location - range.length)]; 
     count++; 
    } 
    return count; 
} 

- (NSUInteger)numberOfOccurrencesOfChar:(char)aChar { 
    const char *cString = [self cStringUsingEncoding:NSUTF8StringEncoding]; 
    NSUInteger stringLength = strlen(cString); 
    NSUInteger count = 0; 
    for (int i = 0; i < stringLength; i++) { 
     if (cString[i] == aChar) { 
      count++; 
     } 
    } 
    return count; 
} 

@end 

В то время как «numberOfOccurrencesOfString:» не выделяет никакой дополнительной памяти и поддерживает строковые иглы, «numberOfOccurrencesOfChar:» выделяет autoreleased с-струнный копию NSString и ищет одиночный знак. ""

Как вы просили подсчет новых строк (отсюда и одиночные символы), я решил, что быстрый результат может быть хорошим для этой конкретной цели: Итак, я взял тестовую строку длиной 2486813, содержащую всего 78312 '\ n ». (Я в основном взял вариацию файла слов OSX) и ... ... ran [testString numberOfOccurrencesOfString: @ "\ n"] 100 раз: 19.35s ... ran [testString numberOfOccurrencesOfChar: '\ n'] 100 раз: 6.91s (Настройка: 2,2 ГГц Core 2 Duo MacBook Pro, работающий на одной нити)

[Изменить: исправлена ​​небольшая ошибка; . Сделал второй фрагмент кода в метод категории строки]

+0

За исключением ..... Откуда берется «testRange»? –

+0

Упс, исправлено. Релиз из версии до того, как я затянул код;) – Regexident

0

Вы можете сканировать через строку, используя SubstringWithRange:

Подсчитайте число раз \ п появляется.

+0

Вы имеете в виду [string substringWithRange: NSMakeRange (i, 1)] для i = 0 ... n? с "isEqualToString: \ n"? Это создало бы автореализованную подстроку с одним символом для каждого отдельного символа. Нехорошо и сравнительно медленно. Но я думаю, вы, вероятно, имели в виду «rangeOfString:»;) См. Мой ответ, используя его. – Regexident

+0

Правда. Я не считал память подстрокиWithRange:. rangeOfString: будет иметь такой же эффект. Но я пытался избежать выполнения домашнего задания OPs. Извините, если это не так, но чтение между строками похоже на это. –

+0

Истинный момент. Я просто подумал, что в любом случае мне понадобится его в собственном проекте, и, таким образом, он не слишком беспокоился: P – Regexident

0

наименьший вы говорите? Это автоматически превращает этот вопрос в код гольф

FILE*f=fopen(path,"r"); 
int i,c; 
while(1+c)i+=(c=fgetc(f))==10; 
printf("%i",i); 

(пожалуйста, не когда-либо фактически использовать этот код)

0

Если Вы хотите остановиться в Cocoa/CocoaTouch, вы можете использовать NSRegularExpression для этого:

NSString *theString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error]; 
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\n" options:NSRegularExpressionCaseInsensitive error:&error]; 
NSUInteger numLines = [regex numberOfMatchesInString:theString options:0 range:NSMakeRange(0, [theString length])] + 1; 
Смежные вопросы