削除/置換する文字数が文字列の長さに比べて少ない場合、while ループでの「衝突」の可能性が小さいため、ソリューションは適切です。各ステップで新しい文字列を割り当てる代わりに、単一の可変文字列を使用してメソッドを改善できます。
NSString *string = @"Remove Some Characters";
int totalRemove = 5;
NSMutableString *result = [string mutableCopy];
for (int j=0; j < totalRemove; j++) {
int replaceLocation;
do {
replaceLocation = arc4random_uniform((int)[result length]);
} while ([result characterAtIndex:replaceLocation] == '_' || [result characterAtIndex:replaceLocation] == ' ');
[result replaceCharactersInRange:NSMakeRange(replaceLocation, 1) withString:@"_"];
}
削除/置換する文字数が文字列の長さとほぼ同じ大きさである場合は、別のアルゴリズムの方が適している可能性があります。
次のコードは、C プログラミング言語の整数配列内の一意の乱数のアイデアを使用して、文字列のすべての文字に対する単一のループでランダムな位置の文字を置き換えます。
スペース文字を置き換えないという要件のため、追加の (最初の) パスが必要です。
NSString *string = @"Remove Some Characters";
int totalRemove = 5;
// First pass: Determine number of non-space characters:
__block int count = 0;
[string enumerateSubstringsInRange:NSMakeRange(0, [string length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
if (![substring isEqualToString:@" "]) {
count++;
}
}];
// Second pass: Replace characters at random positions:
__block int c = count; // Number of remaining non-space characters
__block int r = totalRemove; // Number of remaining characters to replace
NSMutableString *result = [string mutableCopy];
[result enumerateSubstringsInRange:NSMakeRange(0, [result length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
if (![substring isEqualToString:@" "]) {
// Replace this character with probability r/c:
if (arc4random_uniform(c) < r) {
[result replaceCharactersInRange:substringRange withString:@"_"];
r--;
if (r == 0) *stop = YES; // Stop enumeration, nothing more to do.
}
c--;
}
}];
このソリューションのもう 1 つの利点は、サロゲート ペア (絵文字など) と構成された文字シーケンスが、文字列内に2 つの別個の文字として格納されている場合でも、正しく処理されることです。