Search a string with nsmutablearray contents - cocoa

This is probably a quick and easy question, but how would I be able to search a string with the contents of a nsmutablearray which are strings. So I have the NSString *blah = #"djfald.ji". I have the nsmutablearray filled with different extensions and I want to search the string blah to see if any of the extensions have a match. I used to use -[NSRange rangeOfString:] but that doesn't work with arrays.
Thanks,
Kevin

If you really are dealing with path extensions, it's probably better to approach this the other way round. Something like:
NSString *extension = [#"djfald.ji" pathExtension];
BOOL found = [extensions containsObject:extension];

Simply use a block:
NSUInteger extIndex = [extensionArray indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [blah hasSuffix:obj];
}];
NSString *extension = extensionIndex == NSNotFound ? [extensionArray objectAtIndex extIndex] : nil;
Or simply loop through the array with an enumeration.

Related

How to use "valueforkey"?

I'm trying to do the following - I have an Array in which some strings are stored. These strings shall be used to call an NSArray. An example will clarify what I'm trying to do:
This is the working code that I'm trying to achieve ("briefing0" is of type NSArray):
NSString *path = [docsDir stringByAppendingPathComponent:[briefing0 objectAtIndex:indexPath.row]];
This is the "same" code that I'm trying to use:
int i = 0;
NSString *path = [docsDir stringByAppendingPathComponent:[(NSArray *)[NSString stringWithFormat:#"briefing%d", i] objectAtIndex:indexPath.row]];
Any ideas?
Thanks in advance!
Tom
Assuming that briefing0 is actually a property, then yes, this is possible (and not uncommon) in ObjC via KVC.
int i = 0;
NSString *prop = [NSString stringWithFormat:#"briefing%d", i];
NSArray *array = [self valueForKey:prop];
NSString *value = [array objectAtIndex:indexPath.row];
... etc. ...
-valueForKey: is the piece you're looking for. Note that this will throw an exception if you construct a key that does not exist, and so must be used with extreme care.

Convert NSString to few NSIntegers

I have getting data from plist to NSString, in result I see something like this "{{1848,594},{154,176}}". What is the best way to convert every single number to separate NSInteger?
NSString *frame = [myPlistKey objectForKey:#"frame"];
How to convert frame to 4 separate integers?
In this specific case, it looks like you are trying to parse the string representation of an NSRect, in which case you can just use NSRectFromString() from the Foundation framework.
Edit:
Since you are not much specific, I will try to cover your situation. If i count with the fact you have NSString *frame filled with {{1848,594},{154,176}}:
NSString *stringWithoutLeftBracket = [frame
stringByReplacingOccurrencesOfString:#"{" withString:#""];
NSString *stringWithoutRightBracket = [stringWithoutLeftBracket
stringByReplacingOccurrencesOfString:#"}" withString:#""];
NSArray *frameArray = [stringWithoutRightBracket componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]];
Then you can access objects with indexes like:
NSInteger integer = [[frameArray objectAtIndex:0] integerValue];
But also you could use a for loop like this:
for (NSInteger integer in frameArray) {
// Do something
}
In my opinion you have a string made from rect, means you could convert it.

NSTextView + NSTextFinder + my separate NSSearchField

I am trying to implement searching in NSTextView with search query coming from my custom NSSearchField.
Sounds pretty simple, but I cannot get it working.
So far I've looked through all the Apple Documentation about NSTextFinder, its client and FindBarContainer. The TextFinder simply provides the FindBarView to the container, and container shows it when you activate searching.
All the communication between the client, container and TextFinder is hidden. It just looks like a black-box that is designed to work "as is" without any customisation or interference.
But what about - (void)performAction:(NSTextFinderAction)op method of NSTextFinder? Isn't it for sending custom commands to the TextFinder?
I was trying to assign a new search string to it with the following:
NSPasteboard* pBoard = [NSPasteboard pasteboardWithName:NSFindPboard];
[pBoard declareTypes:[NSArray arrayWithObjects:NSPasteboardTypeString, NSPasteboardTypeTextFinderOptions, nil] owner:nil];
[pBoard setString:_theView.searchField.stringValue forType:NSStringPboardType];
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSTextFinderCaseInsensitiveKey,
[NSNumber numberWithInteger:NSTextFinderMatchingTypeContains], NSTextFinderMatchingTypeKey,
nil];
[pBoard setPropertyList:options forType:NSPasteboardTypeTextFinderOptions];
[textFinder performAction:NSTextFinderActionSetSearchString];
but that doesn't work and simply breaks the normal findBar operation.
I have a strong feeling that I am doing something wrong.
All I want is to have a standard search functionality in my own NSSearchField. Is that possible?
I bet I am not the first one who is not happy with normal findBar.
Your help is very needed and appreciated!
For an NSTextView, NSTextFinder is mostly just a user interface for NSString's func range(of searchString: String, options mask: NSString.CompareOptions = [], range rangeOfReceiverToSearch: NSRange) -> NSRange
If you want to implement your own search on an NSTextView, use that. To search forward, you construct a range starting at the end of the current selections's range and going to the end of the NSTextView's text. To search backward, construct a range starting at 0 and going to the beginning of the current selection's range, and tell NSString to use backwards search.
If NSString returns a .notFound range, implement wrap-around yourself.
If you need startsWith, endsWith or wholeWord you'll need to take the result NSString's func gives you, check to see if it will do, and if not adjust the range and call it again.
You can use NSComboBox. Return search value using below delegate:
- (NSString *)comboBox:(NSComboBox *)aComboBox completedString:(NSString *)substring
{
if ([aComboBox tag] == 101 || [aComboBox tag] == 102) {
NSArray *currentList;
if ([aComboBox tag] == 101) {
NSArray *keyArray = keySuggestions;
currentList = keyArray;
} else {
currentList = [NSArray arrayWithArray:self.valueSuggestions];
}
NSEnumerator *theEnum = [currentList objectEnumerator];
id eachString;
NSInteger maxLength = 0;
NSString *bestMatch = #"";
while (nil != (eachString = [theEnum nextObject])) {
NSString *commonPrefix = [eachString
commonPrefixWithString:substring options:NSCaseInsensitiveSearch];
if ([commonPrefix length] >= [substring length] && [commonPrefix
length] > maxLength)
{
maxLength = [commonPrefix length];
bestMatch = eachString;
break;
}
}
return bestMatch;
}
return substring;
}

NSArray Sorting

I have an NSArray with values that I am pulling from an NSDictionary using a selector to sort with which has the following values:
John
Brian
Alex
....
Dave
When I use the code below, since they are being compared as strings, the list comes back with:
NSArray *array = [[[self myDictionary] allValues] sortedArrayUsingSelector:#selector(compare:)];
John
Dave
Brian
...
How can I get these values to sort correctly where they are in order 1, 2, 3, etc.? I've looked at several different examples for sorting, but have not been able to find an example like mine. I must also mention that I'm new to objective-c and iOS. Any help would be greatly appreciated.
Thanks!
I was actually able to figure out the solution. I created an NSComparisonResult block using custom logic to read the number portion off of the front of each string and then comparing them numerically:
NSComparisonResult (^sortByNumber)(id, id) = ^(id obj1, id obj2)
{
//Convert items to strings
NSString *s1 = (NSString *)obj1;
NSString *s2 = (NSString *)obj2;
//Find the period and grab the number
NSUInteger periodLoc1 = [s1 rangeOfString:#"."].location;
NSString *number1 = [s1 substringWithRange:NSMakeRange(0, periodLoc1)];
NSUInteger periodLoc2 = [s2 rangeOfString:#"."].location;
NSString *number2 = [s2 substringWithRange:NSMakeRange(0, periodLoc2)];
//Compare the numeric values of the numbers
return [number1 compare:number2 options:NSNumericSearch];
};
Then I sort my array by calling:
NSArray *array = [[[self myDictionary] allValues] sortedArrayUsingComparator:sortByNumber];

Check for String within a String

I'm trying to compare two strings
NSString strOne = #"Cat, Dog, Cow";
NSString strTwo = #"Cow";
How do I determine if strOne contains strTwo
Try using rangeOfString:
NSRange result = [strOne rangeOfString:strTwo];
From the documentation:
Returns an NSRange structure giving the location and length in the receiver of the first occurrence of aString. Returns {NSNotFound, 0} if aString is not found or is empty (#"").
For anyone needing the code to check is a string exists within a string, here's my code thanks to fbrereto. This example checks to see if any string contained in an array of strings (stringArray) can be found within a string (myString):
int count = [stringArray count];
for (NSUInteger x = 0; x < count; ++x) {
NSRange range = [self.myString rangeOfString:[stringArray objectAtIndex:x]];
if (range.length > 0) {
// A match has been found
NSLog(#"string match: %#",[stringArray objectAtIndex:x]);
}
}
I believe this is the correct syntax for checking if the range exists (correcting response from Kendall):
range.location != NSNotFound
Gradually straying off topic, but I always explode my strings, which would mean just exploding it using your search string as a key and you can use the array count to see how many instances you have.
Just incase anyone is coming from a code language that uses "explode" to blow a string up into an array like me, I found writing my own explode function tremendously helpful, those not using "explode" are missing out:
- (NSMutableArray *) explodeString : (NSString *)myString key:(NSString*) myKey
{
NSMutableArray *myArray = [[NSMutableArray alloc] init];
NSRange nextBreak = [myString rangeOfString:myKey];
while(nextBreak.location != NSNotFound)
{
[myArray addObject: [myString substringToIndex:nextBreak.location]];
myString = [myString substringFromIndex:nextBreak.location + nextBreak.length];
nextBreak = [myString rangeOfString:myKey];
}
if(myString.length > 0)
[myArray addObject:myString];
return myArray;
}
works like this:
[self explodeString: #"John Smith|Age: 37|Account Balance: $75.00" key:#"|"];
which will return this array:
[#"John Smith", #"Age: 37", #"Account Balance: $75.00"];
This lets you quickly pull out a specific value in a tight space, Like if you have a client and you want to know how much money he has:
[[self explodeString: clientData key: pipe] objectAtIndex: 1];
or if you wanted specifically the dollar amount as a float:
[[[self explodeString: [[self explodeString: clientData key: pipe] objectAtIndex: 1] key: #": "] objectAtIndex: 2] floatValue];
anyway I find arrays way easier to work with and more flexible, so this is very helpful to me. Additionally with a little effort you could make an "explodable string" data type for your private library that lets you treat it like a string or return an index value based on the key
ExplodableString *myExplodableString;
myExplodableString.string = #"This is an explodable|string";
NSString *secondValue = [myExplodableString useKey: #"|" toGetValue: index];

Resources