2010-09-10 64 views
6

Tôi đã viết chức năng này mà shuffles các nội dung của một NSString, và nó có vẻ làm việc, nhưng mỗi bây giờ và sau đó nó bị treo. Đây có thể là một đường vòng, nhưng tôi đặt các ký tự vào một mảng, trao đổi các phần tử trong mảng một cách ngẫu nhiên, và sau đó biến mảng trở lại thành một chuỗi.Xáo trộn chữ cái trong một NSString trong mục tiêu-C

Tôi không chắc chắn những gì tôi đang làm là không an toàn làm cho nó sụp đổ. Tôi nghĩ rằng có lẽ tôi đang thiết lập finalLettersString = result, nhưng tôi cũng đã thử finalLettersString = [NSString stringWithString:result] và điều đó cũng bị treo. Lý do tôi bối rối là bởi vì nó không sụp đổ mỗi lần. Tôi chỉ tiếp tục nhấn nút trộn, và đôi khi nó bị treo. Tôi nên tìm nơi nào?

/* This function shuffles the letters in the string finalLettersString */ 

-(IBAction)shuffleLetters:(id)sender{ 
    int length = [finalLettersString length]; 
    NSMutableArray * letters = [NSMutableArray arrayWithCapacity:length]; 
    NSLog(@"final letters: %@", finalLettersString); 
    for(int i = 0; i < length; i++){ 
     char ch = [finalLettersString characterAtIndex:i]; 
     NSLog(@"%c", ch); 
     NSString * cur = [NSString stringWithFormat:@"%c", ch]; 
     [letters insertObject:cur atIndex:i]; 
    } 

    NSLog(@"LETTERS:: %@", letters); 

    for(int i = length - 1; i >= 0; i--){ 
     int j = arc4random() % (i + 1); 
     //NSLog(@"%d %d", i, j); 
     //swap at positions i and j 
     NSString * str_i = [letters objectAtIndex:i]; 
     [letters replaceObjectAtIndex:i withObject:[letters objectAtIndex:j]]; 
     [letters replaceObjectAtIndex:j withObject:str_i];  
    } 
    NSLog(@"NEW SHUFFLED LETTERS %@", letters); 

    NSString * result = @""; 
    for(int i = 0; i < length; i++){ 
     result = [result stringByAppendingString:[letters objectAtIndex:i]]; 
    } 

    NSLog(@"Final string: %@", result); 
    finalLettersString = result; 
    finalLetters.text = finalLettersString; 
} 

Trả lời

8

Nó sẽ là tốt hơn để sao chép nội dung của chuỗi vào một bộ đệm tạm thời loại unichar và shuffle các nội dung của bộ đệm, thay vì tạo nhiều chuỗi nhỏ.

NSUInteger length = [finalLettersString length]; 

if (!length) return; // nothing to shuffle  

unichar *buffer = calloc(length, sizeof (unichar)); 

[finalLettersString getCharacters:buffer range:NSMakeRange(0, length)]; 

for(int i = length - 1; i >= 0; i--){ 
    int j = arc4random() % (i + 1); 
    //NSLog(@"%d %d", i, j); 
    //swap at positions i and j 
    unichar c = buffer[i]; 
    buffer[i] = buffer[j]; 
    buffer[j] = c; 
} 

NSString *result = [NSString stringWithCharacters:buffer length:length]; 
free(buffer); 

// caution, autoreleased. Allocate explicitly above or retain below to 
// keep the string. 
finalLettersString = result; 

Một vài điều bạn sẽ phải coi chừng:

  1. chuỗi Unicode có thể chứa các ký tự composite và cặp thay thế. Xáo trộn những xung quanh sẽ rất có thể dẫn đến một chuỗi không hợp lệ. Trong khi các cặp thay thế rất hiếm, không phải là hiếm khi thấy rằng ký tự é bao gồm hai ký tự (chữ cái viết thường cơ bản e và dấu kết hợp cấp tính). Đối với chuỗi lớn, nó có thể gây ra vấn đề về bộ nhớ vì bạn sử dụng hết 3 lần không gian như chuỗi gốc (1 × cho chuỗi gốc, 2 × cho bộ đệm chúng tôi sử dụng và 3 × cho chuỗi mới). và sau đó quay trở lại 2 × khi chúng tôi giải phóng bộ đệm).

+0

Cảm ơn! Chắc chắn là một giải pháp tốt hơn nhiều. Một vấn đề thực sự là bạn không thể sử dụng NSUIntegers, bởi vì - trên 0 dẫn đến một số thực sự lớn và không -1 kể từ khi unsigned của nó. Tôi đã nhận nó để làm việc bằng cách sử dụng ints và giữ lại. Trong tình huống này, bạn có nghĩ rằng nó là thích hợp hơn để giữ lại hoặc phân bổ một cách rõ ràng? – jkeesh

+0

@jkeesh: Điểm tốt về các số nguyên không dấu. Liên quan đến phân bổ một cách rõ ràng, nó phụ thuộc vào nền tảng đích. Nếu bạn đang nhắm mục tiêu iPhone, một số người nói để tránh các autorelease hồ bơi khi bạn có thể thanh lịch làm như vậy, nhưng đối với Mac OS X (tức là hệ thống với bộ nhớ nhiều hơn so với iPhone) nó sẽ làm cho không có sự khác biệt đáng chú ý. Cá nhân, tôi luôn phân bổ rõ ràng hơn là chống lại một 'autorelease' với một' giữ lại', nhưng kết quả cũng giống nhau. – dreamlax

+0

Trong ngày và tuổi của quốc tế hóa, bạn không thể giả định rằng một bản đồ unichar cho một nhân vật. – JeremyP

11

Một biến thể của mã @ dreamlax không sử dụng mảng char. Không chắc chắn hiệu quả. Nhưng nó không có vấn đề Unicode.

NSMutableString *randomizedText = [NSMutableString stringWithString:currentText]; 

NSString *buffer; 
for (NSInteger i = randomizedText.length - 1, j; i >= 0; i--) 
{ 
    j = arc4random() % (i + 1); 

    buffer = [randomizedText substringWithRange:NSMakeRange(i, 1)]; 
    [randomizedText replaceCharactersInRange:NSMakeRange(i, 1) withString:[randomizedText substringWithRange:NSMakeRange(j, 1)]]; 
    [randomizedText replaceCharactersInRange:NSMakeRange(j, 1) withString:buffer]; 
} 
Các vấn đề liên quan