NSSet to string separaing by comma - ios

I have the next code for converting NSSet to string separating by comma:
-(NSString *)toStringSeparatingByComma
{
NSMutableString *resultString = [NSMutableString new];
NSEnumerator *enumerator = [self objectEnumerator];
NSString* value;
while ((value = [enumerator nextObject])) {
[resultString appendFormat:[NSString stringWithFormat:#" %# ,",value]];//1
}
NSRange lastComma = [resultString rangeOfString:#"," options:NSBackwardsSearch];
if(lastComma.location != NSNotFound) {
resultString = [resultString stringByReplacingCharactersInRange:lastComma //2
withString: #""];
}
return resultString;
}
It seems that it works, but I get here two warnings:
1. format string is not a string literal (potentially insecure)
2. incompatible pointer types assigning to nsmutablestring from nsstring
How to rewrite it to avoid of warnings?

There is another way to achieve what you are trying to do with fewer lines of code:
You can get an array of NSSet objects using:
NSArray *myArray = [mySet allObjects];
You can convert the array to a string:
NSString *myStr = [myArray componentsJoinedByString:#","];

stringByReplacingCharactersInRange method's return type NSString. You are assigning it to NSMutableString. Use mutable copy.
resultString = [[resultString stringByReplacingCharactersInRange:lastComma //2
withString: #""]mutablecopy]

Related

Parse NSString with colons into NSDictionary

I'm trying to parse a string I have that follows the format below
Key: Object\n
Key: Object\n
Key: Object\n
Into an NSDictionary so that it is more easily accessible to me. My question is: Is there a better way to do this that is already incorporated into obj-c? My first thought would be to form an array based on the separation of the : and the newlines and then use the even values as the keys and the odd values as the objects but that seems a little overcomplicated.
NSString *str = #"Key1: Object1\nKey2: Object2\nKey3: Object3\n";
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSArray *lines = [str componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for (NSString *aKeyValue in lines)
{
NSArray *components = [aKeyValue componentsSeparatedByString:#":"];
if ([components count] != 2) continue; //Bypass stranges lines, like the last one
NSString *key = [components[0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *value = [components[1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[dict setObject:value forKey:key];
}
NSLog(#"Dict:\n%#", dict);
This gives:
$> Dict:
{
Key1 = Object1;
Key2 = Object2;
Key3 = Object3;
}
Note: I had to rename your String with different keys, because they need to be unique (else, it would have replace the value keeping only the last one). If it's not the case, you maybe don't want a NSDictionary.
This code should work (in Swift):
func parseString(_ str: String) -> Dictionary<String, String> {
let lines = str.components(separatedBy: .newlines)
var dict = [String: String]()
for line in lines {
let list = line.components(separatedBy: ": ")
if list.count == 2 {
dict[list[0]] = list[1]
}
}
return dict
}
First, we create an array with the lines, then for each line, we extract key and value separated by the colon.
All the solutions offered at the time of writing create an array of lines and then process those lines. NSString provides the method enumerateLinesUsingBlock: to avoid creating this intermediate array of lines. Assuming your string is referenced by the variable str then:
NSMutableDictionary *results = [NSMutableDictionary new];
[str enumerateLinesUsingBlock:^(NSString *line, BOOL *stop)
{
NSArray<NSString *> *kvPair = [line componentsSeparatedByString:#":"]; // split key & value
if (kvPair.count != 2) return; // ignore any line not matching "key : value"
NSString *key = [kvPair[0] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet]; // remove any whitespace
NSString *value = [kvPair[1] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet];
results[key] = value;
}];
will produce the dictionary in results.
Note: The stop parameter passed to the block is to allow the line enumeration to be terminated early, it is not used in this sample. However if a malformed line is found it could be used to terminate the parsing early.
There is no better way to do this with Objective C. Here is how you could approach this. Separate strings by new line character, then again break each line strings with ":", put left part to key and right part to value.
NSString *string = #"name: Jack Johnson\n\
address: Australia\n\
interest: Singing\n\";
NSString *trimmedString = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSArray *keyValuePairs = [trimmedString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSString *keyValuePair in keyValuePairs) {
NSArray *keyValues = [keyValuePair componentsSeparatedByString:#":"];
dict[[keyValues.firstObject stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]] = [keyValues.lastObject stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
NSLog(#"%#", dict);
Something like this. But this gets pretty nice with swift like so,
let keyValueTuple = string.trimmingCharacters(in: .whitespacesAndNewlines)
.components(separatedBy: .newlines)
.map { line -> (String, String) in
let keyValuePairs = line.components(separatedBy: CharacterSet(charactersIn: ":"))
let key = keyValuePairs.first!.trimmingCharacters(in: .whitespaces)
let value = keyValuePairs.last!.trimmingCharacters(in: .whitespaces)
return (key, value)
}
let dict = Dictionary(uniqueKeysWithValues: keyValueTuple)

Split NSString from first whitespace

I have a name textfield in my app, where both the firstname maybe a middle and a lastname is written. Now I want to split these components by the first whitespace, the space between the firstname and the middlename/lastname, so I can put it into my model.
For example:
Textfield Text: John D. Sowers
String 1: John
String 2: D. Sowers.
I have tried using [[self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] firstObject]; & [[self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] lastObject];
But these only work if have a name without a middlename. Since it gets the first and the last object, and the middlename is ignored.
So how would I manage to accomplish what I want?
/*fullNameString is an NSString*/
NSRange rangeOfSpace = [fullNameString rangeOfString:#" "];
NSString *first = rangeOfSpace.location == NSNotFound ? fullNameString : [fullNameString substringToIndex:rangeOfSpace.location];
NSString *last = rangeOfSpace.location == NSNotFound ? nil :[fullNameString substringFromIndex:rangeOfSpace.location + 1];
...the conditional assignment (rangeOfSpace.location == NSNotFound ? <<default value>> : <<real first/last name>>) protects against an index out of bounds error.
Well that method is giving you an array with all the words split by white space, so then you can grab the first object as the first name and the rest of the objects as middle/last/etc
NSArray *ar = [self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *firstName = [ar firstObject];
NSMutableString *rest = [[NSMutableString alloc] init];
for(int i = 1; i < ar.count; i++)
{
[rest appendString:[ar objectAtIndex:i]];
[rest appendString:#" "];
}
//now first name has the first name
//rest has the rest
There might be easier way to do this, but this is one way..
Hope it helps
Daniel
I think this example below I did, solves your problem.
Remember you can assign values from the array directly, without transforming into string.
Here is an example:
NSString *textField = #"John D. Sowers";
NSArray *fullName = [textField componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" "]];
if (fullName.count)
{
if (fullName.count > 2)
{
NSLog(#"Array has more than 2 objects");
NSString *name = fullName[0];
NSLog(#"Name:%#",name);
NSString *middleName = fullName[1];
NSLog(#"Middle Name:%#",middleName);
NSString *lastName = fullName[2];
NSLog(#"Last Name:%#",lastName);
}
else if(fullName.count == 2)
{
NSLog(#"Array has 2 objects");
NSString *name = fullName[0];
NSLog(#"Name:%#",name);
NSString *lastName = fullName[1];
NSLog(#"Last Name:%#",lastName);
}
else
{
NSString *name = fullName[0];
}
}
I found this to be most robust:
NSString *fullNameString = #"\n Barnaby Marmaduke \n \n Aloysius ";
NSMutableArray *nameArray = [[fullNameString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy];
[nameArray removeObject:#""];
NSString *firstName = [nameArray firstObject];
if(nameArray.count)
{
[nameArray removeObjectAtIndex:0];
}
NSString *nameRemainder = [nameArray componentsJoinedByString:#" "];
Bob's your uncle.

Parse all integers from string in Objective-C

I have a problem how to get all integer values from string in Objective-C
NSString *numbers = #"1, 2";
int number = [numbers intValue];
But this just takes the first number (1) but I need both of them.
Thank you guys.
Try something like this:
NSArray *listOfNumbers = [numbers componentsSeparatedByString:#","];
for (NSString *numberAsString in listOfNumbers) {
int number = [numberAsString intValue]; // you might want to trim the string first
}
This is for if they're always separated by a ", ":
NSString *numbers = #"1, 2";
NSArray *numberTokens = [numbers componentsSeparatedByString:#", "];
for (NSString *token in numberTokens) {
NSLog(#"%i", token.integerValue);
}
This solution allows you to specify multiple characters that might separate the numbers:
NSString *numbers = #"1, 2";
NSArray *numberTokens = [numbers componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#", "]];
for (NSString *token in numberTokens) {
if (token.length > 0) {
NSLog(#"%#: %i", token, token.integerValue);
}
}

Unable to extracting a substring from an NSString

I have an input string in the format
"Jerry Lane"(angle bracket)jerry.lane#gmail.com(bracket closed),"Harry Potter"(angle bracket)harry.potter#gmail.com(bracket closed),"Indiana Jones",(angle bracket)indiana.jones#gmail.com(bracket closed),"Tom Cruise"(angle bracket)tom.cruise#gmail.com(bracket closed)
Here, i am supposed to first separate the string on the basis of comma delimiter, which would give me a separate string like
"Jerry Lane"(angle bracket)jerry.lane#gmail.com(bracket closed)
Then i need to save extract the string between the <> brackets, which is essentially the string "jerry.lane#gmail.com". I am using the following code, but it is giving me the following error:
Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFConstantString substringWithRange:]: Range or index out of bounds'
-(NSArray *)parseString:(NSString *)string
{
if(string)
{
NSArray *myArray = [string componentsSeparatedByString:#","];
for(NSMutableString *myString in myArray)
{
NSRange start,end;
start = [myString rangeOfString:#"<"];
end = [myString rangeOfString:#">"];
if(start.location != NSNotFound && end.location != NSNotFound)
{
NSString *emailAddress = [myString substringWithRange:NSMakeRange(start.location,end.location)];
NSString *name = [myString substringToIndex:start.location];
NSDictionary *myDictionary = [[NSDictionary alloc] init];
[myDictionary setValue:emailAddress forKey:#"Dhruvil Vyas"];
[testArray addObject:myDictionary];
}
}
}
return testArray;
}
The arguments that substring takes are the start position and the length
Not the start position and the end position.
More Info
borrrden's answer is correct. Here is another way to do this.
-(NSArray *)parseString:(NSString *)string
{
if(string)
{
NSArray *myArray = [string componentsSeparatedByString:#","];
for(NSMutableString *myString in myArray)
{
NSArray *tempNameArray = [myString componentsSeparatedByString:#"<"];
NSString *email = [tempNameArray objectAtIndex:1];
NSArray *tempMailArray = [email componentsSeparatedByString:#">"];
NSString *emailAddress = [tempMailArray objectAtIndex:0];
NSString *name = [tempNameArray objectAtIndex:0];
NSDictionary *myDictionary = [[NSDictionary alloc] init];
[myDictionary setValue:emailAddress forKey:#"Dhruvil Vyas"];
[testArray addObject:myDictionary];
}
}
return testArray;
}

Split NSString and Limit the response

I have a string Hello-World-Test, I want to split this string by the first dash only.
String 1:Hello
String 2:World-Test
What is the best way to do this? What I am doing right now is use componentsSeparatedByString, get the first object in the array and set it as String 1 then perform substring using the length of String 1 as the start index.
Thanks!
I added a category on NSString to split on the first occurrence of a given string. It may not be ideal to return the results in an array, but otherwise it seems fine. It just uses the NSString method rangeOfString:, which takes an NSString(B) and returns an NSRange showing where that string(B) is located.
#interface NSString (Split)
- (NSArray *)stringsBySplittingOnString:(NSString *)splitString;
#end
#implementation NSString (Split)
- (NSArray *)stringsBySplittingOnString:(NSString *)splitString
{
NSRange range = [self rangeOfString:splitString];
if (range.location == NSNotFound) {
return nil;
} else {
NSLog(#"%li",range.location);
NSLog(#"%li",range.length);
NSString *string1 = [self substringToIndex:range.location];
NSString *string2 = [self substringFromIndex:range.location+range.length];
NSLog(#"String1 = %#",string1);
NSLog(#"String2 = %#",string2);
return #[string1, string2];
}
}
#end
Use rangeOfString to find if split string exits and then use substringWithRange to create new string on bases of NSRange.
For Example :
NSString *strMain = #"Hello-World-Test";
NSRange match = [strMain rangeOfString:#"-"];
if(match.location != NSNotFound)
{
NSString *str1 = [strMain substringWithRange: NSMakeRange (0, match.location)];
NSLog(#"%#",str1);
NSString *str2 = [strMain substringWithRange: NSMakeRange (match.location+match.length,(strMain.length-match.location)-match.length)];
NSLog(#"%#",str2);
}

Resources