I am trying to search an NSMutableArray for a string. I am using containsObject: currently but it looks like this is case sensitive. I need to search for all combinations of the given string (trip). Any ideas would be greatly appreciated.
if ([self.theArray containsObject:trip]) {
}
Not that hard:
BOOL found = NO;
for (NSString* str in self.theArray) {
if ([str caseInsensitiveCompare:trip] == NSOrderedSame) {
found = YES;
break;
}
}
Create a category for NSArray and add this function in there.
- (BOOL)containsStringCaseInsensitive:(NSString *)key {
key = [key lowercaseString];
for (int i = ([self count] - 1); i >= 0; i--) {
NSObject * obj = [self objectAtIndex:i];
if ([obj isKindOfClass:[NSString class]]) {
NSString * strInArray = [(NSString *)obj lowercaseString];
if ([key isEqualToString:strInArray]) {
return YES;
}
}
}
return NO;
}
How about a block:
__block trip = #"blah";
if (NSNotFound!=[self.theArray indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop)
{
if (NSOrderedSame==[(NSString *)obj caseInsensitiveCompare:trip])
{
stop=YES;
return YES;
}
return NO;
}])
{
NSLog(#"It's a MATCH!");
}
Related
I have a NSString which holds info like this:
%hook APMIntro
- (bool)isIntroductoryOffer {
return NO;
}
%end
%hook APMIntro
- (void)setIntroductoryOffer:(bool)arg1 {
arg1 = NO;
%orig;
}
%end
%hook ChallengeProgressHolder
- (void)setHasItem:(bool)arg1 {
arg1 = NO;
%orig;
}
%end
%hook ChallengeProgressHolder
- (bool)hasItem {
return NO;
}
%end
The end result I'm trying to achieve is this
%hook APMIntro
- (bool)isIntroductoryOffer {
return NO;
}
- (void)setIntroductoryOffer:(bool)arg1 {
arg1 = NO;
%orig;
}
%end
%hook ChallengeProgressHolder
- (void)setHasItem:(bool)arg1 {
arg1 = NO;
%orig;
}
- (bool)hasItem {
return NO;
}
%end
So far, I've tried using NSMutableArray to separate the different lines to try and organize them - but the result is an infinite loop. I've tried this code so far
-(NSString *)cleanUp:(NSString *)cleanUp{
NSMutableArray *content = [[cleanUp componentsSeparatedByString:#"%hook "] mutableCopy];
// NSMutableArray *content = [[NSMutableArray alloc] init];
NSMutableArray *cleaned = [[NSMutableArray alloc] init];
NSMutableArray *hooks = [[NSMutableArray alloc] init];
// NSArray *messy = [[cleanUp componentsSeparatedByString:#"\n"] mutableCopy];
cleanUp = #"";
NSString *line, *line1;
//NSString *fixMe = #"";
for (unsigned h = 1; h < content.count; h++){
line = [content objectAtIndex:h-1];
if ([line hasPrefix:#"#import"]){
[cleaned addObject:[NSString stringWithFormat:#"%#\n", line]];
continue;
} else {
cleanUp = [NSString stringWithFormat:#"%#%%hook %#", cleanUp, line];
//[content addObject:[NSString stringWithFormat:#"%hook %#", line]];
}
}
//NSLog(#"\n\n\n%#\n\n\n", cleanUp);
BOOL lookingForEnd = NO;
BOOL hookFound = NO;
hooks = [[cleanUp componentsSeparatedByString:#"\n"] mutableCopy];
// NSString *hook;
//NSLog(#"\n\n\n%#\n\n\n", hooks);
for (unsigned i = 1; i < hooks.count; i++){
line = [hooks objectAtIndex:i-1];
//NSLog(#"%i: %#\n\n", i, line);
if (lookingForEnd) {
[cleaned addObject:[NSString stringWithFormat:#"%#\n", line]];
if ([line isEqualToString:#"%end"]){
lookingForEnd = NO;
//i = 1;
continue;
} else if ([line1 isEqualToString:line]){
lookingForEnd = YES;
}
}
if ([line hasPrefix:#"%hook"]){
line1 = line;
for (unsigned j = 1; j < hooks.count; j++){
printf("\n\n\nHOOK\n\n\n");
if ([[hooks objectAtIndex:j-1] isEqual:line1]){
printf("\n\n\nFOUND\n\n\n");
[hooks addObject:line];
[cleaned addObject:[NSString stringWithFormat:#"%#\n", line]];
lookingForEnd = YES;
hookFound = YES;
//break;
}
}
}
}
NSLog(#"%#\n", cleaned);
return cleaned;
}
After setting this up and reading further into how to sort arrays - I found that I'm going about this all wrong - I'm just not sure how to go about doing it right.
Thanks in advance - any help is greatly appreciated
You possibly could do this all with a complex RegEx -- but, here's a bit of a "step by step" approach.
Create a NSObject class with two string properties - blockName and blockBody.
We'll use this regular expression:
(^%hook )(.*?)(?=%end$)
to split the string into "pieces" of text contained between "%hook " and "%end".
Then, we'll loop through the matches creating an array of "block" objects, each with the name and body.
Next, we sort the array by blockName.
Finally, we loop through the sorted array, formatting an output string with the "bodies" grouped into the named blocks.
So, if we have:
MyBlock.h
#interface MyBlock : NSObject
#property (strong, nonatomic) NSString *blockName;
#property (strong, nonatomic) NSString *blockBody;
#end
MyBlock.m
#import "MyBlock.h"
#implementation MyBlock
#end
and we start with your sample NSString:
%hook APMIntro
- (bool)isIntroductoryOffer {
return NO;
}
%end
%hook APMIntro
- (void)setIntroductoryOffer:(bool)arg1 {
arg1 = NO;
%orig;
}
%end
%hook ChallengeProgressHolder
- (void)setHasItem:(bool)arg1 {
arg1 = NO;
%orig;
}
%end
%hook ChallengeProgressHolder
- (bool)hasItem {
return NO;
}
%end
We can do this:
NSString *input = [self sampleString];
NSMutableArray <MyBlock *> *blocks = [NSMutableArray new];
NSString *pattern = #"(^%hook )(.*?)(?=%end$)";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators | NSRegularExpressionAnchorsMatchLines error:NULL];
NSArray *myArray = [regex matchesInString:input options:0 range:NSMakeRange(0, [input length])] ;
for (NSTextCheckingResult *match in myArray) {
// get the range starting after "%hook "
NSRange matchRange = [match rangeAtIndex:2];
// get the "block" string
NSString *s = [input substringWithRange:matchRange];
// split it by newLines
NSArray <NSString *> *a = [s componentsSeparatedByString:#"\n"];
// we want the "body" to skip the first line
NSRange r;
r.location = 1;
r.length = [a count] - 1;
// get the lines excluding the first line
NSArray <NSString *> *a2 = [a subarrayWithRange:r];
// new MyBlock object
MyBlock *b = [MyBlock new];
b.blockName = [a firstObject];
b.blockBody = [a2 componentsJoinedByString:#"\n"];
[blocks addObject:b];
}
// sort the array of blocks by blockName
NSArray <MyBlock *> *sortedArray;
sortedArray = [blocks sortedArrayUsingComparator:^NSComparisonResult(MyBlock *a, MyBlock *b) {
return [a.blockName compare:b.blockName];
}];
NSMutableString *output = [NSMutableString new];
NSString *curName = #"";
// loop through the array of blocks
for (int i = 0; i < [sortedArray count]; i++) {
MyBlock *b = sortedArray[i];
// if we're at a "new" blockName
if (![curName isEqualToString:b.blockName]) {
curName = b.blockName;
// add %end if output is not ""
if ([output length] != 0) {
[output appendString:#"%end\n"];
}
// add a new line of %hook blockName
[output appendFormat:#"\n%%hook %#\n", curName];
}
// add the block body
[output appendFormat:#"%#", b.blockBody];
}
// "close" the last block
[output appendString:#"%end\n"];
// log the resulting string
NSLog(#"%#", output);
and the output from that sample is:
%hook APMIntro
- (bool)isIntroductoryOffer {
return NO;
}
- (void)setIntroductoryOffer:(bool)arg1 {
arg1 = NO;
%orig;
}
%end
%hook ChallengeProgressHolder
- (void)setHasItem:(bool)arg1 {
arg1 = NO;
%orig;
}
- (bool)hasItem {
return NO;
}
%end
Play with the output formatting (line breaks, spacing, etc) as desired :)
I have 100 key and value in nsmutabledictornary and i want to check that any value have null or not. Do you have any short function or technique?
I don't want to multiple line code like check every key and value. Your answer would be appreciated.
This code will give you the set of keys which have (non)null values. You can't store actual nil values in a dictionary, so [NSNull null] is assumed. The predicate is trivially alterable to any other condition.
NSDictionary *d = #{ #"a" : #"1", #"b" : [NSNull null] };
NSSet *nullKeys = [d keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return [d[key] isKindOfClass:[NSNull class]];
}];
NSSet *nonnullKeys = [d keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return [d[key] isKindOfClass:[NSNull class]] == NO;
}];
From here, you can use the keys to generate a corresponding dictionary, if needed.
NSMutableDictionary *nonNullDict = [NSMutableDictionary dictionary];
[d enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if ([nonnullKeys contains:key]) {
nonNullDict[key] = obj;
}
}];
If you don't need a separate list of keys, and just need the filtered dictionary, skip the first step and modify the second part to read as follows:
NSMutableDictionary *nonNullDict = [NSMutableDictionary dictionary];
[d enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSNull null]] == NO) {
nonNullDict[key] = obj;
}
}];
Write category on NSDictionary it will provide you null free dictionary. Here is the category I have written for myself.
code for .h file (interface)
#import <Foundation/Foundation.h>
#interface NSDictionary (CheckNull)
{
}
- (NSDictionary *)nullFreeDictionary;
#end
Code for .m file. (implementation)
#import "NSDictionary+CheckNull.h"
#implementation NSDictionary (CheckNull)
- (NSDictionary *) nullFreeDictionary
{
NSMutableDictionary *tempDictionary = [self mutableCopy];
for (NSString *key in tempDictionary.allKeys) {
NSString *value = [tempDictionary valueForKey:key];
if ([value isKindOfClass:[NSString class]]) {
if (value == (id)[NSNull null] || value == nil || value.length == 0) {
[tempDictionary setValue:#"" forKey:key];
}
}
}
return tempDictionary;
}
Call null free method on your dictionary using above category.
NSDictionary *dict = [dict nullFreeDictionary];
//To remove NULL from Dictionary
-(NSMutableDictionary *)removeNullFromDictionary : (NSMutableDictionary *)dict
{
// if (![dict isKindOfClass:[NSMutableDictionary class]])
// {
// }
dict = [[NSMutableDictionary alloc] initWithDictionary:dict];
for (NSString * key in [dict allKeys])
{
if ([dict[key] isKindOfClass:[NSNull class]])
{
[dict setValue:#"" forKey:key];
}
else if ([dict[key] isKindOfClass:[NSMutableDictionary class]]||[dict[key] isKindOfClass:[NSDictionary class]])
{
dict[key] = [self removeNullFromDictionary:[NSMutableDictionary dictionaryWithDictionary:dict[key]]];
}
else if ([dict[key] isKindOfClass:[NSMutableArray class]]||[dict[key] isKindOfClass:[NSArray class]])
{
dict[key] = [self removeNullFromArray:[NSMutableArray arrayWithArray:dict[key]]];
}
}
return dict;
}
//To remove NULL from Array
-(NSMutableArray *)removeNullFromArray : (NSMutableArray *)arr
{
// if (![arr respondsToSelector:#selector(addObject:)])
// {
// arr = [[NSMutableArray alloc] initWithArray:arr];
// }
arr = [[NSMutableArray alloc] initWithArray:arr];
for (int cnt = 0; cnt<[arr count]; cnt++)
{
if ([arr[cnt] isKindOfClass:[NSNull class]])
{
arr[cnt] = #"";
}
else if ([arr[cnt] isKindOfClass:[NSMutableDictionary class]]||[arr[cnt] isKindOfClass:[NSDictionary class]])
{
arr[cnt] = [self removeNullFromDictionary:[NSMutableDictionary dictionaryWithDictionary:arr[cnt]]];
}
else if ([arr[cnt] isKindOfClass:[NSMutableArray class]]||[arr[cnt] isKindOfClass:[NSArray class]])
{
arr[cnt] = [self removeNullFromArray:[NSMutableArray arrayWithArray:arr[cnt]]];
}
}
return arr;
}
I have a Array of custom objects with object having following properties optionID,OptionText. I want to get comma separated string for the optionID property. What would be the best approach to do this in iOS SDK.
for example NSString CommaSeperted = #"1,3,5" etc.
Category to NSArray:
#implementation NSArray(CustomAdditions)
- (NSString *)commaSeparatedStringWithSelector:(SEL)aSelector
{
NSMutableArray *objects = [NSMutableArray array];
for (id obj in self)
{
if ([obj respondsToSelector:aSelector]) {
IMP method = [obj methodForSelector:aSelector];
id (*func)(id, SEL) = (void *)method;
id customObj = func(obj, aSelector);
if (customObj && [customObj isKindOfClass:[NSString class]]) {
[objects addObject:customObj];
}
}
}
return [objects componentsJoinedByString:#","];
}
#end
Example:
#implementation NSDictionary(Test)
- (NSString*)optionID
{
return [self objectForKey:#"optionID"];
}
- (NSString*)OptionText
{
return [self objectForKey:#"OptionText"];
}
#end
NSArray *customObjects = #[#{#"optionID": #"id1", #"OptionText": #"text1" }, #{#"optionID" : #"id2", #"OptionText": #"text2"}];//List of Your custom objects
NSString *commaSeparatedOptionIDs = [customObjects commaSeparatedStringWithSelector:NSSelectorFromString(#"optionID")];
NSString *commaSeparatedOptionTexts = [customObjects commaSeparatedStringWithSelector:NSSelectorFromString(#"OptionText")];
Try this
NSString *commaSeparatedStringOfID = #"";
for (CustomClass *object in yourArray){
commaSeparatedStringOfID = [commaSeparatedStringOfID stringByAppendingString:[NSString stringWithFormat:#"%#,"]];
}
// removing last comma
commaSeparatedStringOfID = [commaSeparatedStringOfID substringToIndex:[commaSeparatedStringOfID length]-1];
commaSeparatedStringOfID will be your required string.
I was looking into implementing hashtag autocomplete with objective-C as shown in the picture
I found it a bit difficult than expected. I'm looking more specific implementation for adding and deleting hashtags. For example, the hashtag should be deleted as a whole at once. I was wondering if anyone has similar experience implemented it and if there's a more efficient way implemented it. Thanks
I ended up writing some functions that I feel is a bit ugly but it works. Maybe there are some more efficient ways to implement it.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//user is a singleton instance
User *user = [User sharedUser];
user.autocompleteTableView.hidden = NO;
int identifiedTagsStringLength = [self.identifiedTagsString length];
int cursorLocation = range.location;
//insert characters
if (range.location >= identifiedTagsStringLength) {
NSString *newSearch =#"";
NSRange newRange;
if(identifiedTagsStringLength != 0) {
newSearch = [urlField.text substringFromIndex:identifiedTagsStringLength];
newRange = NSMakeRange(range.location - identifiedTagsStringLength, 0);
}
else {
newSearch = textField.text;
newRange = range;
}
NSString *substring = [NSString stringWithString:newSearch];
substring = [substring stringByReplacingCharactersInRange:newRange withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
if (cursorLocation > currentTagsRange) {
currentTagsRange = cursorLocation;
}
}
//delete tags
else {
if ([self.ranges count] != 0 && cursorLocation < currentTagsRange) {
int rangeLength = [self.ranges count];
int toBeRemovedIndex = 0;
for (int i = 0; i< rangeLength; i++) {
if (cursorLocation >= [[self.ranges objectAtIndex:i][0] intValue]
&& cursorLocation <= [[self.ranges objectAtIndex:i][1] intValue]) {
toBeRemovedIndex = i;
}
}
[self.tags removeObjectAtIndex:toBeRemovedIndex];
[self updateRanges];
NSString *outputString = #"";
for (NSString *tag in self.tags) {
outputString = [NSString stringWithFormat:#"%##%# ", outputString,
tag];
}
urlField.text = outputString;
self.identifiedTagsString = urlField.text;
currentTagsRange = [outputString length] - 1;
}
}
return YES;
}
- (void)updateRanges {
self.ranges = [[NSMutableArray alloc] init];
int startIndex = 0;
for (NSString *tag in self.tags) {
startIndex = [self.ranges count] == 0 ? 0 : [[self.ranges lastObject][1] intValue] + 1;
int tagLength = [tag length];
NSArray *range = [NSArray arrayWithObjects:[NSNumber numberWithInt:startIndex], [NSNumber numberWithInt:startIndex + tagLength + 1], nil];
[self.ranges addObject: range];
}
}
#pragma mark UITableViewDataSource methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if (self.identifiedTagsString == NULL) {
self.identifiedTagsString = #"";
}
[self.tags addObject: selectedCell.textLabel.text];
[self updateRanges];
NSString *output = #"";
for (NSString *tag in self.tags) {
output = [NSString stringWithFormat:#"%##%# ", output, tag];
}
urlField.text = output;
User *user = [User sharedUser];
user.autocompleteTableView.hidden = YES;
self.identifiedTagsString = urlField.text;
currentTagsRange = [urlField.text length];
}
I try to find item in array by index
http://content.screencast.com/users/xdozorx/folders/Jing/media/cb5e24cf-9349-4aa2-a886-bfafb96299f5/00000051.png
here my code.
- (NSDictionary *) getItemAtIntex:(int) index inArray:(NSArray *) array
{
for (NSDictionary *item in array)
{
if (enumerateIndex == index)
{
NSLog(#"%#",item[#"comment"]);
return item;
}
else if ([item[#"childs"] count])
{
enumerateIndex ++;
[self getItemAtIntex:index inArray:item[#"childs"]];
}
}
return nil;
}
I call my method
enumerateIndex = 0;
NSDictionary *comment = [self getItemAtIntex:indexPath.row inArray:comments];
for example, with index 1, in debug I have two answers
subGL 1 -> 1
global 2
I need in response only subGL 1 -> 1
here my file https://www.dropbox.com/s/mvc21a8pl5n6xz3/commenst.json
You aren't doing anything with the return value of the recursive call. Try this:
- (NSDictionary *) getItemAtIntex:(int) index inArray:(NSArray *) array
{
for (NSDictionary *item in array)
{
if (enumerateIndex == index)
{
NSLog(#"%#",item[#"comment"]);
return item;
}
else if ([item[#"childs"] count])
{
enumerateIndex ++;
NSDictionary *result = [self getItemAtIntex:index inArray:item[#"childs"]];
if (result) {
return result;
}
}
}
return nil;
}