2009-06-02 42 views
31

Tôi có một số NSString hoặc NSMutableString và muốn nhận được số lần xuất hiện của một ký tự cụ thể.Số lần xuất hiện của một ký tự trong NSString

Tôi cần thực hiện việc này cho một vài ký tự - chữ hoa tiếng Anh trong trường hợp này - vì vậy sẽ rất tuyệt khi nó được nhanh chóng.

Trả lời

1

tôi có lẽ sẽ sử dụng

NSString rangeOfCharacterFromSet:

hoặc

rangeOfCharacterFromSet:options:range::

nơi tập là tập hợp các ký tự mà bạn đang tìm kiếm. Nó trả về với vị trí của ký tự đầu tiên khớp với tập hợp. Giữ mảng hoặc từ điển và tăng số đếm cho ký tự, sau đó lặp lại.

+0

Nếu tôi hiểu Tài liệu chính xác, điều này sẽ cung cấp phạm vi của bất kỳ ký tự nào trong tập hợp. Nhưng tôi cần đếm * mỗi * ký tự. – Elliot

+1

ý tưởng của tôi là để giữ từ điển của char -> đếm cặp và sau đó nhận được char tại chỉ số nhất định và tăng nó đếm trong từ điển ... hoặc bạn chỉ có thể lặp qua chuỗi và kiểm tra xem mỗi nhân vật trong tập của bạn, nếu nó sau đó tăng số đếm là – stefanB

7

Bất cứ khi nào bạn đang tìm kiếm mọi thứ trong một NSString, trước tiên hãy thử sử dụng NSScanner.

NSString *yourString = @"ABCCDEDRFFED"; // For example 
NSScanner *scanner = [NSScanner scannerWithString:yourString]; 

NSCharacterSet *charactersToCount = @"C" // For example 
NSString *charactersFromString; 

if (!([scanner scanCharactersFromSet:charactersToCount 
          intoString:&charactersFromString])) { 
    // No characters found 
    NSLog(@"No characters found"); 
} 

// should return 2 for this 
NSInteger characterCount = [charactersFromString length]; 
+0

tôi chưa thể làm được điều này. Tôi đang cố gắng đếm số lượng không gian. – lawrence

+3

@lawrence Theo mặc định, không gian và khoảng trống được bỏ qua bởi NSScanner. – borrrden

+3

Bạn có thể gọi 'setCharactersToBeSkipped: (NSCharacterSet *) skipSet' với' nil' là 'skipSet' - và' NSScanner' sẽ không bỏ qua bất kỳ ký tự nào. –

1

Ví dụ về Máy quét bị lỗi trên iPhone. Tôi đã tìm thấy giải pháp này:

NSString *yourString = @"ABCCDEDRFFED"; // For example 
NSScanner *mainScanner = [NSScanner scannerWithString:yourString]; 
NSString *temp; 
NSInteger numberOfChar=0; 
while(![mainScanner isAtEnd]) 
{ 
    [mainScanner scanUpToString:@"C" intoString:&temp]; 
    numberOfChar++; 
    [mainScanner scanString:@"C" intoString:nil]; 
} 

Nó làm việc cho tôi mà không gặp sự cố. Hy vọng nó có thể giúp!

2

giải pháp của bạn không làm việc cho tôi, tôi đã thêm một điều kiện trong vòng lặp để tăng numberOfChar chỉ khi mainScanner đã đạt đến cuối chuỗi:

NSString *yourString = @"ABCCDEDRFFED"; // For example 
NSScanner *mainScanner = [NSScanner scannerWithString:yourString]; 
NSString *temp; 
NSInteger numberOfChar=0; 
while(![mainScanner isAtEnd]) 
{ 
    [mainScanner scanUpToString:@"C" intoString:&temp]; 
    if(![mainScanner isAtEnd]) { 
     numberOfChar++; 
     [mainScanner scanString:@"C" intoString:nil]; 
    } 
} 

Lưu ý rằng đây là một sửa chữa nhanh chóng, tôi don không có thời gian để làm một giải pháp tao nhã ...

96

Bạn có thể thực hiện việc này trong một dòng. Ví dụ, đây đếm số lượng chỗ:

NSUInteger numberOfOccurrences = [[yourString componentsSeparatedByString:@" "] count] - 1; 
+5

Tạo một mảng tạm thời mặc dù .. Đối với tốc độ, [câu trả lời của Jacque] (http://stackoverflow.com/a/15947190/482601) nên được ưu tiên. – fabian789

+1

Điều này có tính không gian ở đầu và cuối 'yourString' không? –

+0

Sự khác biệt về tốc độ sẽ chỉ quan trọng nếu bạn đang thực hiện hàng nghìn lần. –

22

Hãy thử thể loại này trên NSString:

@implementation NSString (OccurrenceCount) 

- (NSUInteger)occurrenceCountOfCharacter:(UniChar)character 
{ 
    CFStringRef selfAsCFStr = (__bridge CFStringRef)self; 

    CFStringInlineBuffer inlineBuffer; 
    CFIndex length = CFStringGetLength(selfAsCFStr); 
    CFStringInitInlineBuffer(selfAsCFStr, &inlineBuffer, CFRangeMake(0, length)); 

    NSUInteger counter = 0; 

    for (CFIndex i = 0; i < length; i++) { 
     UniChar c = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, i); 
     if (c == character) counter += 1; 
    } 

    return counter; 
} 

@end 

Cái này là nhanh hơn so với phương pháp componentsSeparatedByString: khoảng 5 lần.

+0

Danh mục này hoạt động tốt, nhưng tôi có một câu hỏi: bạn có thể sử dụng cả UniChar (từ CFString.h) và unichar (từ NSString) như là giống nhau không? – Bjinse

5

Ngày nay điều đầu tiên mà tôi suy nghĩ của tôi cho một cái gì đó như thế: NSCountedSet

NSString *string [email protected]"AAATTC"; 

NSMutableArray *array = [@[] mutableCopy]; 

[string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { 
    [array addObject:substring]; 
}] ; 
NSCountedSet * set = [[NSCountedSet alloc] initWithArray:array]; 

for (NSString *nucleobase in @[@"C", @"G", @"A", @"T"]){ 
    NSUInteger count = [set countForObject:nucleobase]; 
    NSLog(@"%@: %lu", nucleobase, (unsigned long)count); 
} 

bản ghi:

C: 1 
G: 0 
A: 3 
T: 2 
0

Đây là một phiên bản làm việc Swift 3, cho NSRange, Range, String và NSString! Thưởng thức :)

/// All ranges using NSString and NSRange 
/// Is usually used together with NSAttributedString 

extension NSString { 
    public func ranges(of searchString: String, options: CompareOptions = .literal, searchRange: NSRange? = nil) -> [NSRange] { 
     let searchRange = searchRange ?? NSRange(location: 0, length: self.length) 
     let subRange = range(of: searchString, options: options, range: searchRange) 
     if subRange.location != NSNotFound { 

      let nextRangeStart = subRange.location + subRange.length 
      let nextRange = NSRange(location: nextRangeStart, length: searchRange.location + searchRange.length - nextRangeStart) 
      return [subRange] + ranges(of: searchString, options: options, searchRange: nextRange) 
     } else { 
      return [] 
     } 
    } 
} 

/// All ranges using String and Range<Index> 
/// Is usually used together with NSAttributedString 

extension String { 
    public func ranges(of searchString: String, options: CompareOptions = [], searchRange: Range<Index>? = nil) -> [Range<Index>] { 
     if let range = range(of: searchString, options: options, range: searchRange, locale: nil) { 

      let nextRange = range.upperBound..<(searchRange?.upperBound ?? endIndex) 
      return [range] + ranges(of: searchString, searchRange: nextRange) 
     } else { 
      return [] 
     } 
    } 
} 
Các vấn đề liên quan