Re: NSString, scramble
Re: NSString, scramble
- Subject: Re: NSString, scramble
- From: Michel Haver <email@hidden>
- Date: Mon, 02 Jul 2001 23:09:26 +0200
On 7/1/01 16:45, "Fritz Anderson" <email@hidden> wrote:
>
At 2:38 PM +0200 7/1/2001, Michel M.J. Haver wrote:
>
> I want to read a couple of string and then scramble the strings by mixing
>
> the characters in the strings to new ad random positions.
>
>
>
> Problem Description by Example
>
> I want to convert a string like for example "heart" to "retah"
>
> or the next time you run the program the example string "heart" will be
>
> converted in an other random scramble string like "tarhe".
>
>
>
> How I can implement such a random string scramble functionality with the
>
> cocoa objects NSString, NSMutableString is something of a riddle to me which
>
> I am working to find out.
>
>
>
> Does someone has some tips for solving this riddle?
>
>
A solution appears at the end of this message. It is the complete
>
source for a Foundation tool that makes an anagram of each argument
>
passed to the tool.
>
>
> I prefer to do it in Cocoa or is it should this kind of string manipulation
>
> be done in C or C++?
>
>
That's a separate question. The NSString solution works for any
>
Unicode string, and handles dynamic-memory issues in a
>
guaranteed-safe fashion. If called repeatedly, the overhead of
>
dynamic allocation (I'm thinking particularly of the single-unichar
>
substrings) would become a performance problem. In the unlikely
>
event makeAnagram is called a huge number of times without releasing
>
the current autorelease pool, there would be a memory problem (which,
>
under Mac OS X, shows up first as a performance problem).
>
>
The memory problem could be lessened by allocating an
>
NSAutoreleasePool before the huge number of calls to makeAnagram, and
>
periodically releasing and reallocating it.
>
>
You could improve performance inside makeAnagram by calling [self
>
getCharacters:] to get a copy of the string's characters in a C array
>
of unichar, scrambling the array, and then passing the array to
>
[NSString stringWithCharacters: length:] to produce the returned
>
string. With this approach, my [swapCharacterAtIndex: withIndex:] is
>
unnecessary, and [makeAnagram] can return NSString *.
>
>
I didn't do this because (1) the "more efficient" way only just
>
occurred to me; and (2) my example does have the advantage of being a
>
close translation of your own.
>
>
Absolutely ruthless optimization might drive you to give up Unicode
>
support and work directly with ASCII C strings.
>
>
-- F
>
>
#import <Foundation/Foundation.h>
>
#import <stdlib.h>
>
#import <time.h>
>
>
unsigned randRange(unsigned lowIncluded, unsigned highExcluded);
>
>
// Return an unsigned integer in the range [low .. high)
>
inline
>
unsigned randRange(unsigned lowIncluded,
>
unsigned highExcluded)
>
{
>
return lowIncluded + ((unsigned) random()) % (highExcluded - lowIncluded);
>
}
>
>
@interface NSMutableString (Anagrams)
>
- (void) swapCharacterAtIndex: (unsigned) indexOne
>
withIndex: (unsigned) indexTwo;
>
@end
>
>
@interface NSString (Anagrams)
>
- (NSMutableString *) makeAnagram;
>
@end
>
>
@implementation NSMutableString (Anagrams)
>
>
- (void) swapCharacterAtIndex: (unsigned) indexOne
>
withIndex: (unsigned) indexTwo
>
{
>
unichar firstCharacter = [self characterAtIndex: indexOne],
>
secondCharacter = [self characterAtIndex: indexTwo];
>
NSString * firstString = [NSString stringWithCharacters: &firstCharacter
>
length: 1];
>
NSString * secondString = [NSString stringWithCharacters: &secondCharacter
>
length: 1];
>
>
[self replaceCharactersInRange: NSMakeRange(indexOne, 1)
>
withString: secondString];
>
[self replaceCharactersInRange: NSMakeRange(indexTwo, 1)
>
withString: firstString];
>
}
>
>
@end
>
>
@implementation NSString (Anagrams)
>
>
- (NSMutableString *) makeAnagram
>
{
>
NSMutableString * retval = [self mutableCopy];
>
unsigned i;
>
>
for (i = 0; i < [self length]; i++) {
>
[retval swapCharacterAtIndex: i withIndex: randRange(0, [self
>
length])];
>
}
>
>
return [retval autorelease];
>
}
>
>
@end
>
>
int main (int argc, const char * argv[])
>
{
>
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
>
NSArray * arguments = [[NSProcessInfo processInfo] arguments];
>
int i;
>
>
// Seed the random number generator
>
srandom(time(NULL));
>
>
for (i = 1; i < [arguments count]; i++) {
>
NSString * fromString = [arguments objectAtIndex: i];
>
>
NSString * anagram = [fromString makeAnagram];
>
>
printf("%s\n", [anagram cString]);
>
}
>
>
[pool release];
>
return 0;
>
}
Fritz,
I am still bewildered by the quick answer on my question. I tried your
solution and it worked after I added
NSMutableArray * arguments = [[NSProcessInfo processInfo]
arguments];
[arguments addObject:@"Here's a string!"];
The NSMutableArray Gives no warning NSArray doesn't respond to "addObject"
The addition [arguments addObject:@"Here's a string!"];
results in a compiler waring NSArray Gives warning NSArray doesn't respond
to "addObject"
With NSArray * arguments = [[NSProcessInfo processInfo]
arguments];
Output of your program
'e ti!nHgrrse sa
Jul 02 22:42:20 anagram[1052] String out: 'e ti!nHgrrse sa.
anagram.app has exited with status 0.
Questions:
I want to implement this construction in my cocoa application.
How can I use @implementation NSString (Anagrams) without the NSMutableArray
construction?
Learning by example code makes the steep learning more manageable, so is
there a depot with cocoa example code other than the ADC examples?
Cheers,
Michel
#import <Foundation/Foundation.h>
//#import <stdlib.h>
//#import <time.h>
unsigned randRange(unsigned lowIncluded, unsigned highExcluded);
// Return an unsigned integer in the range [low .. high)
inline
unsigned randRange(unsigned lowIncluded,
unsigned highExcluded)
{
return lowIncluded + ((unsigned) random()) % (highExcluded -
lowIncluded);
}
@interface NSMutableString (Anagrams)
- (void) swapCharacterAtIndex: (unsigned) indexOne
withIndex: (unsigned) indexTwo;
@end
@interface NSString (Anagrams)
- (NSMutableString *) makeAnagram;
@end
@implementation NSMutableString (Anagrams)
- (void) swapCharacterAtIndex: (unsigned) indexOne
withIndex: (unsigned) indexTwo
{
unichar firstCharacter = [self characterAtIndex: indexOne],
secondCharacter = [self characterAtIndex: indexTwo];
NSString * firstString = [NSString stringWithCharacters:
&firstCharacter
length: 1];
NSString * secondString = [NSString stringWithCharacters:
&secondCharacter
length: 1];
[self replaceCharactersInRange: NSMakeRange(indexOne, 1)
withString: secondString];
[self replaceCharactersInRange: NSMakeRange(indexTwo, 1)
withString: firstString];
}
@end
@implementation NSString (Anagrams)
- (NSMutableString *) makeAnagram
{
NSMutableString * retval = [self mutableCopy];
unsigned i;
for (i = 0; i < [self length]; i++) {
[retval swapCharacterAtIndex: i withIndex: randRange(0, [self
length])];
}
return [retval autorelease];
}
@end
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray * arguments = [[NSProcessInfo processInfo]
arguments];
// NSArray * arguments = [[NSProcessInfo processInfo]
arguments];
int i;
// Seed the random number generator
srandom(time(NULL));
// NSLog(@"String out: %@.\n", arguments);
//add object to the array arguments
// NSArray * arguments = [[NSProcessInfo processInfo]
arguments];
// With NSArray Gives warning NSArray doesn't respond to "addObject"
// With NSMutableArray Gives no warning NSArray doesn't respond to
"addObject"
[arguments addObject:@"Here's a string!"];
// Print the contents of the array.
//NSLog(@"Array description: %@ \n", arguments);
for (i = 1; i < [arguments count]; i++) {
NSString * fromString = [arguments objectAtIndex: i];
NSString * anagram = [fromString makeAnagram];
printf("%s\n", [anagram cString]);
NSLog(@"String out: %@.\n", anagram);
}
[pool release];
return 0;
}