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)
Related
I have an array of dictionary in the following format.
mainArray[0] = { "key1" : "aText", "key2" :"Text to replace A" }
mainArray[1] = { "key1" : "bText", "key2" :"Text to replace B" }
and so on.
I have an nsstring which can contain any random text. But if there is an occurrence of "aText" in the string it has to be replaced with the corresponding key2 value as "Text to replace A" and similarly for the rest of the array.
How can this be done just by using nspredicates/ with out any looping?
NOTE:
My current solution is as follows:
NSArray arrayForKey1 = [mainArray valueForKey:#"key1"];
NSArray arrayForKey2 = [mainArray valueForKey:#"key2"];
for (int i = 0; i < mainArray.count; i ++) {
MyString = [MyString stringByReplacingOccurrencesOfString : [arrayForKey1 objectAtIndex:i]
withString : [arrayForKey2 objectAtIndex:i]
options : NSCaseInsensitiveSearch
range : NSMakeRange(0, MyString.length)
];
}
The key1 and key2 keys are useless if you want to map aText to Text to replace a.
What you could have is:
NSMutableString *input = [#"aText apple bText banana cText carrot" mutableCopy];
NSDictionary *replacements = { #"aText" : #"Text to replace a",
#"bText" : #"Text to replace b",
#"cText" : #"Text to replace c" };
for (NSString *rep in replacements)
{
[input replaceOccurrencesOfString:rep withString:[replacements objectForKey:rep]];
}
This will work as long as the replacement strings do not contain any of the search strings, otherwise they could be replaced twice.
Whats is the best way to parse this out?
String:
UMversion=2.9&UMstatus=Approved&UMauthCode=152058&UMrefNum=59567592&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=YYY&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=1&UMbatchRefNum=91016&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=A&UMauthAmount=10&UMfiller=filled
I get this back from the web service as one big long string. Each of the variables are listed then they have a = sign then what I need to populate the variable with.
I need to get all of this data into variables to check them.
So, how should I go about breaking it down.
Use this kind of code:
NSArray* components = [veryLongString componentsSeparatedByString:#"&"]; // array of strings like "x=y"
NSMutableDictionary* parsedResult = [NSMutableDictionary new];
for (NSString* keyValuePair in components) {
NSArray* keyAndValue = [keyValuePair componentsSeparatedByString:#"="];
NSString* key = keyAndValue[0];
NSString* value = (keyAndValue.count>1) ? keyAndValue[1] : nil;
// remove percent escapes in case we have URL-encoded characters in the value like '%20' and the like
parsedResult[key] = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] ?: [NSNull null];
}
NSLog(#"dictionary of parameters: %#", parsedResult);
You will end up with a dictionary containing the keys and values extracted from your string.
NSString* firstPass = [sourceString stringByReplacingOccurrencesOfString:#"&" withString:#"\",\""];
NSString* secondPass = [firstPass stringByReplacingOccurrencesOfString:#"=" withString:#"\":\""];
NSString* grandFinale = [NSString stringWithFormat:#"{\"%#\"}"];
NSData* jsonSource = [grandFinale dataUsingEncoding:NSUTF8Encoding];
NSError* error = nil;
NSDictionary* theBiggie = [NSJSONSerialization JSONObjectWithData:jsonSource options:0 error:&error];
I think NSJSONSerialization will automagically fix up the percent encoding. If not, run grandFinale through stringByRemovingPercentEncoding.
I'm trying to collect the parameters from my ip camera and pass them into individual strings in Objective-C (an iOS app). When I enter the following URL in any web browser: [http://192.168.1.10:92/get_camera_params.cgi] the following is displayed onto the screen:
var resolution=32;
var brightness=136;
var contrast=4;
var mode=2;
var flip=3;
var fps=0;
I would like to collect and pass this values into my own strings such as:
myResolution = 32;
myBrightness = 136;
...................
My guess is that I need to somehow convert the response of the URL into a string and somehow break that string into an array of strings or 6 strings and collect the data in between "=" and ";" in individual strings?
Even though the actual values are Int's, the values must be stored in individual strings for my further code compatibility.
As much as it looks easy, I'm not sure how to approach this, I had a good go at it but didn't advance to anything that is worth putting here on the forum.
Please help with an example.
I'd really appreciate it.
if the response ist non-html, the following should work:
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
NSCharacterSet* charSetToReplace = [NSCharacterSet characterSetWithCharactersInString:#";\r"];
// get content from url
NSString* urlContent = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://192.168.1.10:92/get_camera_params.cgi"] encoding:NSUTF8StringEncoding error:nil];
// split content into rows
NSArray* lines = [urlContent componentsSeparatedByString:#"\n"];
for(NSString* line in lines)
{
//split row
NSArray* comps = [line componentsSeparatedByString:#"="];
if(comps.count < 2)
continue;
// [comp objectAtIndex:0] is the value left of =
// [comp objectAtIndex:1] is the value right of =
// left string without the 'var '
NSString* varName = [[comps objectAtIndex:0] stringByReplacingOccurrencesOfString:#"var " withString:#""];
// right string with trimming the ';'
int varValue = [[[comps objectAtIndex:1] stringByTrimmingCharactersInSet:charSetToReplace] intValue];
// write into dictionary
[dict setObject:[NSString stringWithFormat:#"%d",varValue] forKey:varName];
}
// as int
int myResolution = [[dict objectForKey:#"resolution"] intValue];
int myBrightness = [[dict objectForKey:#"brightness"] intValue];
// or as String
NSString* myResolutionStr = [dict objectForKey:#"resolution"];
NSString* myBrightnessStr = [dict objectForKey:#"brightness"];
// and so on ...
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]
When I use NSXMLParser to parse XML in iPhone app, I know how to do it in the scenario like this:
> <title>L3178 : Freiensteinau Richtung Grebenhain</title> // From XML
But, if I want to extract data from a list, e.x. I want to get the lat and lon from <>id>, how should I deal with that?
<>id>
http://www.freiefahrt.info/?id=468B0243-E15C-4580-9AD2 14D8CF692999&lon=9.3495&lat=50.49465&country=DE&filter=0&expires=2013-12-20T03:13:00
<>/id>
It is very strange if I use instead of <>id>, it will disappear. So, I have to use this ugly notation.
Thank you in advance!
Create a method which extracts parameters from urlString
- (NSDictionary *)paramsFromURLString:(NSString *)urlString
{
NSRange range = [urlString rangeOfString:#"?"];
NSString *subString = [urlString substringFromIndex:range.location+range.length];
NSArray *components = [subString componentsSeparatedByString:#"&"];
NSMutableDictionary *params = [NSMutableDictionary dictionary];
for (NSString *string in components) {
NSRange subRange = [string rangeOfString:#"="];
NSString *key = [string substringToIndex:subRange.location];
NSString *value = [string substringFromIndex:subRange.location+subRange.length];
[params setObject:value forKey:key];
}
return params;
}
From the params find the lat and lon
NSString *urlString = #"http://www.freiefahrt.info/?id=468B0243-E15C-4580-9AD2 14D8CF692999&lon=9.3495&lat=50.49465&country=DE&filter=0&expires=2013-12-20T03:13:00";
NSDictionary *params = [self paramsFromURLString:urlString];
NSString *latitude = params[#"lat"];
NSString *longitude = params[#"lon"];