Converting NSString to key value pair - objective-c

I have a response from server which is NSString and looks like this
resp=handshake&clientid=47D3B27C048031D1&success=true&version=1.0
I want to convert it to key value pair , something like dictionary or in an array .
I couldn't find any useful built-in function for decoding the NSString to NSdictionary and replacing the & with space didn't solve my problem , can anyone give me any idea or is there any function for this problem ?

This should work (off the top of my head):
NSMutableDictionary *pairs = [NSMutableDictionary dictionary];
for (NSString *pairString in [str componentsSeparatedByString:#"&"]) {
NSArray *pair = [pairString componentsSeparatedByString:#"="];
if ([pair count] != 2)
continue;
[pairs setObject:[pair objectAtIndex:1] forKey:[pair objectAtIndex:0]];
}
or you could use an NSScanner, though for something as short as a query string the extra couple of arrays won't make a performance difference.

Related

removing null from arrays in Object-c

I have this snipped of code that results in an array with a whole bunch of "<null>" throughout and I need to figure out how to remove them. Obviously after smashing my head against the keyboard I'm asking for some help.
In my .h I have declared:
NSArray *sortedContacts;
NSArray *rawContacts;
And then in .m:
-(void) buildContacts {
ABAddressBook *addressBook = [ABAddressBook sharedAddressBook];
NSArray *contacts = [addressBook people];
rawContacts=contacts;
NSArray *firstNames = [rawContacts valueForKey:#"First"];
NSArray *lastNames = [rawContacts valueForKey:#"Last"];
NSArray *organization = [rawContacts valueForKey:#"Organization"];
NSMutableArray *fullNames = [NSMutableArray array];
for(int i = 0; i < [firstNames count]; i++)
{
NSString *fullName = [NSString stringWithFormat:#"%# %# %#",
[firstNames objectAtIndex:i],
[lastNames objectAtIndex:i],
[organization objectAtIndex:i]];
[fullNames addObject:fullName];
}
NSMutableArray *fullList = [[NSMutableArray alloc]initWithArray:fullNames];
[fullList removeObjectIdenticalTo: #"<null>"];
sortedContacts = [fullList sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"%#",sortedContacts);
}
I've tried so many things that I just can't see the forest for the trees anymore.
The text <null> is how the singleton instance of NSNull describes itself. That is, it's what -[NSNull description] returns.
In turn, these NSNull objects are getting into your firstNames, lastNames, and organization arrays because that's what Key-Value Coding does when you call -valueForKey: on an array and some of the elements return nil when that message is forwarded on to them with the same key. That is, calling [rawContacts valueForKey:#"First"] causes NSArray to call [element valueForKey:#"First"] for each element in rawContacts and to put the result in the array it builds. But, since an array can't contain nil, if one of those elements returns nil from [element valueForKey:#"First"], an NSNull object is added in its place.
Then, you are formatting the string fullName from the corresponding elements of firstNames, lastNames, and organization. You need to check if any of those elements are NSNull using if ([value isKindOfClass:[NSNull class]]) and handling that. For instance, you might just skip that record. Or you might combine the available fields and leave out any unavailable ones.
In any case, none of the elements of fullList will be #"<null>" because formatting values into #"%# %# %#" can never result in that string. (It might be #"<null> <null> <null>" or something like that, but never just #"<null>".)
A quick look at your code suggests you cannot get any empty strings added to your array, (a) you add elements using:
[fullNames addObject:fullName];
and fullName is created using:
[NSString stringWithFormat:#"%# %# %#" ...
so even if the %#'s get replaced by nothing you'll still have 2 spaces...
Maybe this is why all the things you've tried fail, if you're looking for empty strings you won't find them.
(Addendum: Question now says you're looking for #"<null>", you won't get that either for the same reason - there is at least two spaces in your string.)
The simple answer to removing invalid entries in fullNames is not to add them in the first place. You are adding elements in a loop (for), and conditional logic (e.g. if) inside the loop to determine whether you have something valid to add - however you define "something valid" - and only add an item to fullNames if so.
HTH
I'm not really familiar with the AddressBook framework, however this might be what's causing the confusion:
The values you collect in your arrays firstNames, lastNames and organization can be of type NSString or NSNull. You have to do any null-checking within the for-loop, before the fullName-string is constructed.
Remove this useless line:
[fullList removeObjectIdenticalTo: #"<null>"];
And replace the contents of your for-loop with the following code:
for(int i = 0; i < [firstNames count]; i++)
{
NSString *firstName = [firstNames objectAtIndex:i];
NSString *lastName = [lastNames objectAtIndex:i];
NSString *org = [organization objectAtIndex:i];
NSMutableArray *namesArray = [NSMutableArray array];
if ([firstName isKindOfClass:[NSString class]])
[namesArray addObject:firstName];
if ([lastName isKindOfClass:[NSString class]])
[namesArray addObject:lastName];
if ([org isKindOfClass:[NSString class]])
[namesArray addObject:org];
if (namesArray.count > 0)
[fullNames addObject:[namesArray componentsJoinedByString:#" "]];
}

Convert a String into an array with Keycodes

today i started with a simple Project that should convert a string into an array with keycodes to simulate keystrokes.
My Problem is that i cant use a char as an id for a dictionary to convert that char into the keycode.
//Declare a Dictionary
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
//Add the Basic data for keycodes (i know that there are some missing)
[dictionary setObject:#"0x00" forKey:#"a"]; //a
[dictionary setObject:#"0x0B" forKey:#"b"]; // b
[dictionary setObject:#"0x08" forKey:#"c"]; //c
[dictionary setObject:#"0x02" forKey:#"d"]; // d
[dictionary setObject:#"0x0E" forKey:#"e"]; //e
[dictionary setObject:#"0x03" forKey:#"f"]; //f
[dictionary setObject:#"0x05" forKey:#"g"]; //g
[dictionary setObject:#"0x04" forKey:#"h"]; //h
[dictionary setObject:#"0x22" forKey:#"i"]; //i
[dictionary setObject:#"0x26" forKey:#"j"]; //j
[dictionary setObject:#"0x28" forKey:#"k"]; //k
[dictionary setObject:#"0x25" forKey:#"l"];//l
[dictionary setObject:#"0x2D" forKey:#"m"];//m
[dictionary setObject:#"0x2E" forKey:#"n"];//n
[dictionary setObject:#"0x1F" forKey:#"o"];//o
[dictionary setObject:#"0x23" forKey:#"p"];//p
[dictionary setObject:#"0x0C" forKey:#"q"];//q
[dictionary setObject:#"0x0F" forKey:#"r"];//r
[dictionary setObject:#"0x01" forKey:#"s"];//s
[dictionary setObject:#"0x11" forKey:#"t"];//t
[dictionary setObject:#"0x20" forKey:#"u"];//u
[dictionary setObject:#"0x09" forKey:#"v"];//v
[dictionary setObject:#"0x0D" forKey:#"w"];//w
[dictionary setObject:#"0x07" forKey:#"x"];//x
[dictionary setObject:#"0x10" forKey:#"y"];//y
[dictionary setObject:#"0x06" forKey:#"z"];//z
NSString *workwith = [_mess stringValue]; //Get String from Interface
long stringl = [workwith length]; //Get lenght of the String
int a = 0;
char text[stringl-1]; //make a array with the lenght of the string
while (a < stringl) { //fill this array with chars from the string
text[a] = [workwith characterAtIndex:a];
NSLog(#"%c",text[a]);
a++;
}
char fmat[stringl-1]; //make a second char to fill it with keycodes
int dnehmen = 0;
while (dnehmen <= stringl-1) {
fmat[dnehmen] = [dictionary objectForKey:#"%c",text[dnehmen]]; //stuck at this point
}
At the last line i try to use a char from the first array as an id for the dictionary to get the keycode for the second array.
I get an error that i cant use a char as an id and so i need a was to get the keycode from a char.
(I read some Posts on this site but i didn`t really understood what they´ve done)
Thanks for your answers
Tim
The error you report is down to the line:
fmat[dnehmen] = [dictionary objectForKey:#"%c",text[dnehmen]];
as #"%c",text[dnehmen] does not return an object but a char value due to the use of the rather obscure C comma operator - a comma is usually a separator but is also an operator (like + etc.) which just returns its second argument. So you get an error referring to characters...
Given that you've used NSString values as keys what you need is a string containing your character and you probably meant to type:
fmat[dnehmen] = [dictionary objectForKey:[NSString stringWithFormat:#"%c",text[dnehmen]]];
While that will fix your first problem you now have another, your dictionary returns an NSString containing four characters and your code suggests you'd like the byte (char) represented by those four characters when interpreted by a compiler as a hexadecimal literal...
At this point you might be tempted to try to convert the string into a byte value by parsing it as a hexadecimal number, but you shouldn't. Instead look at putting the value you need into the NSDictionary in the first place. Both the objects any keys used in an NSDictionary can be any [1] type of object. You might want to consider using NSNumber objects for both.
Hopefully that will set you off on the right track in fixing your design.
[1] Well almost any to be precise, any which have equality and hash methods - which in practice is everything that descends from NSObject so don't worry about this pedantic detail now!

How does one populate an NSMutable array of NSMutableSets?

I am using this code in a loop to populate an NSMutable Array of NSMutableSets (of NSString objects). The index of the NSSet is based on the length of the word.
// if set of this length not initialized yet, initialize set.
wordIndex = [NSString stringWithFormat:#"%d", currentWordLength];
if ([myWordArray objectForKey:wordIndex] == nil)
[myWordArray setObject:[[NSMutableSet alloc] initWithObjects:currentWord, nil] forKey:wordIndex];
else
[[myWordArray objectForKey:wordIndex] addObject:currentWord];
The final intention is to split up an array of words into an array of sets of words grouped by their lengths.
However, I see that [myWordArray count] is 0 after this. Why?
You are confusing the methods of NSMutableDictionary and NSMutableArray: In Objective-C arrays do not have keys but have indexes. If you change the class for myWordArray to NSMutableDicitionary it should work.
Try this, it looks very much like your logic, but (1) it uses NSNumbers as keys, which makes a little more sense, (2) handles the missing set condition more simply, but just adding the set, and (3) breaks up the source lines somewhat for easier debugging...
NSArray *inputStrings = // however these are initialized goes here
NSMutableDictionary *result = [NSMutableDictionary dictionary];
for (NSString *currentString in inputStrings) {
NSInteger currentWordLength = currentString.length;
wordIndex = [NSNumber numberWithInt:currentWordLength];
NSMutableSet *wordSet = [result objectForKey:wordIndex];
if (!wordSet) {
wordSet = [NSMutableSet set];
[result setObject:wordSet forKey:wordIndex];
}
[wordSet addObject:currentWord];
}
If you still have an empty dictionary after running this, it might be simpler to watch what's happening by stepping through it.

How to append NSString wiht number?

I'm new in Cocoa.
I have NSString - (e.g) MUSIC . I want to add some new NSString in Array,
And want to check something like this
if MUSIC already contained in Array, add Music_1 , after Music_2 and so on.
So I need to be able read that integer from NSString, and append it +1 .
Thanks
Use
NSString *newString = [myString stringByAppendingString:[NSString stringWithFormat:#"_%i", myInteger]];
if myString is "music", newString will be "music_1" or whatever myInteger is.
EDIT: I seem to have gotten the opposite meaning from the other answer provided. Can you maybe clarify what it is you are asking exactly?
Check it out:
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"123", #"qqq", nil];
NSString *myString = #"MUSIC";
NSInteger counter = 0;
if ([array containsObject:myString]){
NSString *newString = [NSString stringWithFormat:#"%#_%d", myString, ++counter];
[array addObject:newString];
}
else
[array addObject:myString];
For checking duplicate element in Array you can use -containsObject: method.
[myArray containsObject:myobject];
If you have very big array keep an NSMutableSet alongside the array.Check the set for the existence of the item before adding to the array. If it's already in the set, don't add it. If not, add it to both.
If you want unique objects and don't care about insertion order, then don't use the array at all, just use the Set. NSMutableSet is a more efficient container.
For reading integer from NSString you can use intValue method.
[myString intValue];
For appending string with number you can use - (NSString *)stringByAppendingString:(NSString *)aString or - (NSString *)stringByAppendingFormat:(NSString *)format ... method.
Here's how you convert a string to an int
NSString *myStringContainingInt = #"5";
int myInt = [myStringContainingInt intValue];
myInt += 1;
// So on...

Sorting NSStrings of Numbers

So I have an NSDictionary where the keys are years as NSString's and the value for each key is also an NSString which is sort of a description for the year. So for example, one key is "943 B.C.", another "1886". The problem I am encountering is that I want to sort them, naturally, in ascending order.
The thing is that the data source of these years is already in order, it's just that when I go ahead and call setValue:forKey the order is lost, naturally. I imagine figuring out a way to sort these NSString's might be a pain and instead I should look for a method of preserving the order at the insertion phase. What should I do? Should I instead make this an NSMutableArray in which every object is actually an NSDictionary consisting of the key being the year and the value being the description?
I guess I just answered my own question, but to avoid having wasted this time I'll leave this up in case anyone can recommend a better way of doing this.
Thanks!
EDIT: I went ahead with my own idea of NSMutableArray with NSDictionary entries to hold the key/value pairs. This is how I am accessing the information later on, hopefully I'm doing this correctly:
// parsedData is the NSMutableArray which holdes the NSDictionary entries
for (id entry in parsedData) {
NSString *year = [[entry allKeys] objectAtIndex:0];
NSString *text = [entry objectForKey:year];
NSLog(#"Year: %#, Text: %#", year, text);
}
Maintain a NSMutableArray to store the keys in order, in addition to the NSDictionary which holds all key-value pairs.
Here is a similar question.
You could either do it as an array of dictionaries, as you suggest, or as an array of strings where the strings are the keys to your original dictionary. The latter is probably a simpler way of going about it. NSDictionary does not, as I understand it, maintain any particular ordering of its keys, so attempting to sort the values there may be unwise.
I needed to solve a similar problem to sort strings of operating system names, such as "Ubuntu 10.04 (lucid)".
In my case, the string could have any value, so I sort by tokenizing and testing to see if a token is a number. I'm also accounting for a string like "8.04.2" being considered a number, so I have a nested level of tokenizing. Luckily, the nested loop is typically only one iteration.
This is from the upcoming OpenStack iPhone app.
- (NSComparisonResult)compare:(ComputeModel *)aComputeModel {
NSComparisonResult result = NSOrderedSame;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
NSArray *tokensA = [self.name componentsSeparatedByString:#" "];
NSArray *tokensB = [aComputeModel.name componentsSeparatedByString:#" "];
for (int i = 0; (i < [tokensA count] || i < [tokensB count]) && result == NSOrderedSame; i++) {
NSString *tokenA = [tokensA objectAtIndex:i];
NSString *tokenB = [tokensB objectAtIndex:i];
// problem: 8.04.2 is not a number, so we need to tokenize again on .
NSArray *versionTokensA = [tokenA componentsSeparatedByString:#"."];
NSArray *versionTokensB = [tokenB componentsSeparatedByString:#"."];
for (int j = 0; (j < [versionTokensA count] || j < [versionTokensB count]) && result == NSOrderedSame; j++) {
NSString *versionTokenA = [versionTokensA objectAtIndex:j];
NSString *versionTokenB = [versionTokensB objectAtIndex:j];
NSNumber *numberA = [formatter numberFromString:versionTokenA];
NSNumber *numberB = [formatter numberFromString:versionTokenB];
if (numberA && numberB) {
result = [numberA compare:numberB];
} else {
result = [versionTokenA compare:versionTokenB];
}
}
}
[formatter release];
return result;
}