Objective-C Split a String and get last item - objective-c

I have a string like so:
NSString *path = #"\\fake\aaa\bbb\ccc\ddd\eee.pdf";
and I split the string into an array like so:
NSArray *array = [path componentsSeparatedByString:#"\"];
Now there are two things I need here.
I need a string with everything except eee.pdf
I need the last item in the array as a string (eee.pdf)
How would I do this?

Just for fun, there is a little-known way to get an NSURL with its benefit from a windows file path
NSString *path = #"\\\\fake\\aaa\\bbb\\ccc\\ddd\\eee.pdf";
NSURL *url = CFBridgingRelease(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)path, kCFURLWindowsPathStyle, false));
NSString *fileName = url.lastPathComponent;
NSString *parentDirectory = url.URLByDeletingLastPathComponent.path;
Finally you have to convert parentDirectory back to windows path style (backslashes).
But if you mean POSIX paths used in OS X, it's much easier
NSString *path = #"/fake/aaa/bbb/ccc/ddd/eee.pdf";
NSURL *url = [NSURL fileURLWithPath:path];
NSString *fileName = url.lastPathComponent;
NSString *parentDirectory = url.URLByDeletingLastPathComponent.path;

I think you're trying to get the filepath and filename from a full path. There are better ways of doing that. But since you simply asked for the question, here's my answer. Please note that this is not the best approach. In addition, you have to escape the backslashes by using a preceding backslash.
NSString *path = #"\\fake\\aaa\\bbb\\ccc\\ddd\\eee.pdf";
NSArray *array = [path componentsSeparatedByString:#"\\"];
NSMutableArray *removedArray = [[NSMutableArray alloc] init];
for(int i=0; i< array.count -1; i++){
[removedArray addObject:[array objectAtIndex:i]];
}
NSString *joinedString =[removedArray componentsJoinedByString:#"\\"];
NSString *fileName = [array lastObject];
NSLog(#"Path: %#", joinedString);
NSLog(#"Filename: %#", fileName);

For the last element use the lastObject property of the NSArray.
For a string without the last element use subarrayWithRange: using array.count-1 for the NSRange length.
Then join the remaining array with componentsJoinedByString:.
NSString *fileName = [array lastObject];
NSArray *newArray = [array subarrayWithRange:NSMakeRange(0, array.count-1)];
NSString *directoryPath = [newArray componentsJoinedByString:#"\\"];

Related

Trim NSString to specific pathComponent [duplicate]

This question already has answers here:
How to take NSString after specific character which occurs multiple time in NSString?
(3 answers)
Closed 8 years ago.
I have an NSString which represents paths like
.../App/Some/Directory/myClass.mm
Now I want to trim
.../App/Some/Directory/
to get only the Class' name/file. How to achieve this?
You can convert your string to a NSURL, and the get the lastPathComponent to get the "myClass.mm" you want.
NSString* filePath = #"/App/Some/Directory/myClass.mm";
NSURL *url = [NSURL URLWithString:filePath];
NSString* lastComponent = [url lastPathComponent];
Should do the trick.
You can separate the string into components (using the / as the separator), and then the filename will be the last element of the output array.
NSString *input = #".../App/Some/Directory/myClass.mm";
NSArray *array = [input componentsSeparatedByString:#"/"];
NSLog( #"%#", [array lastObject] );
NSString class has lastPathComponent method, also you can solve your problem like this:
NSString *path;
NSString *trimmed;
NSRange range = [path rangeOfString:#"/" options:NSBackwardsSearch];
if (range.location != NSNotFound)
trimmed = [path substringFromIndex:range.location+1];
else
trimmed = path;
NSString* str = #"/App/Some/Directory/myClass.mm";
NSRange replaceRange = [str rangeOfString:#"/myClass.mm"];
if (replaceRange.location != NSNotFound){
NSString* result = [str stringByReplacingCharactersInRange:replaceRange withString:#""];
NSLog(#"Result :%#",result);
}

appending string- works with string with one word but not two

I'm appending a string to a url which then inputs into a database, it works with a single worded string e.g
NSString * string = #"one";
however if my string has two words such as
NSString * string = #"one two";
it does not work. Please see the code below.
NSMutableString * urlString = [NSMutableString stringWithString:url];
[urlString appendString:[NSString stringWithFormat:#"?%#=%#",kWord,word]];
The problem obviously lies with stringWithFormat;
turns out the problem is with the space.
Space characters (and certain others) are not allowed in URLs. You need to convert the space to %20. Here is the proper solution:
NSString *url = #"http://example.com/process.php";
NSString *kword = #"param";
NSString *word = #"one two";
NSMutableString * urlString = [url mutableCopy];
[urlString appendFormat:#"?%#=%#", kWord, [word stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
I have tried couple exampes here, hope it helps.
NSString *string1 = #"String1";
NSString *string2 = #"String2 String3";
NSMutableString *appendingString=[NSMutableString stringWithString: [string1 stringByAppendingString:string2]];
NSLog(#"String1:%# String2:%#",string1,string2);
NSLog(#"StringwithAppend:%#",appendingString);
//------
NSString *url=#"www.abc.com";
NSMutableString * urlString = [NSMutableString stringWithString:url];
NSLog(#"URL String before append:%#",urlString);
NSString *kWord=#"key";
NSString *word=#"word";
[urlString appendString:[NSString stringWithFormat:#"?%#=%#",kWord,word]];
NSLog(#"URL String after append:%#",urlString);
Console Log:
String1:String1 String2:String2 String3
StringwithAppend:String1String2 String3
URL String before append:www.abc.com
URL String after append:www.abc.com?key=word
Try it this way.
NSString * urlString= [NSString stringWithFormat:#"%#?%#=%#", url, kword, word];

How to parse a string format like [***]***?

I need to parse a string like [abc]000, and what I want to get is an array containing abc and 000. Is there an easy way to do it?
I'm using code like this:
NSString *sampleString = #"[abc]000";
NSArray *sampleParts = [sampleString componentsSeparatedByString:#"]"];
NSString *firstPart = [[[sampleParts objectAtIndex:0] componentsSeparatedByString:#"["] lastObject];
NSString *lastPart = [sampleParts lastObject];
But it's inefficient and didn't check whether the string is in a format like [**]**.
For this simple pattern, can just parse yourself like:
NSString *s = #"[abc]000";
NSString *firstPart = nil;
NSString *lastPart = nil;
if ([s characterAtIndex: 0] == '[') {
NSUInteger i = [s rangeOfString:#"]"].location;
if (i != NSNotFound) {
firstPart = [s substringWithRange:NSMakeRange(1, i - 1)];
lastPart = [s substringFromIndex:i + 1];
}
}
Or you could learn to use the NSScanner class.
As always, there are lots of ways to do this.
OPTION 1
If these are fixed length strings (each part is always three characters) then you can simply get the substrings directly:
NSString *sampleString = #"[abc]000";
NSString *left = [sampleString substringWithRange:NSMakeRange(1, 3)];
NSString *right = [sampleString substringWithRange:NSMakeRange(5, 3)];
NSArray *parts = #[ left, right ];
NSLog(#"%#", parts);
OPTION 1 (shortened)
NSArray *parts = #[ [sampleString substringWithRange:NSMakeRange(1, 3)],
[sampleString substringWithRange:NSMakeRange(5, 3)] ];
NSLog(#"%#", parts);
OPTION 2
If they aren't always three characters, then you can use NSScanner:
NSString *sampleString = #"[abc]000";
NSScanner *scanner = [NSScanner scannerWithString:sampleString];
// Skip the first character if we know that it will always start with the '['.
// If we can not make this assumption, then we would scan for the bracket instead.
scanner.scanLocation = 1;
NSString *left, *right;
// Save the characters until the right bracket into a string which we store in left.
[scanner scanUpToString:#"]" intoString:&left];
// Skip the right bracket
scanner.scanLocation++;
// Scan to the end (You can use any string for the scanUpToString that doesn't actually exist...
[scanner scanUpToString:#"\0" intoString:&right];
NSArray *parts = #[ left, right ];
NSLog(#"%#", parts);
RESULTS (for all options)
2013-05-10 00:25:02.031 Testing App[41906:11f03] (
abc,
000
)
NOTE
All of these assume well-formed strings, so you should include your own error checking.
try like this ,
NSString *sampleString = #"[abc]000";
NSString *pNRegex = #"\\[[a-z]{3}\\][0-9]{3}";
NSPredicate *PNTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", pNRegex];
BOOL check=[PNTest evaluateWithObject:sampleString ];
NSLog(#"success:%i",check);
if success comes as 1 then you can perform the action for separating string into array.

save CLLocation to a plist

I'm struggling to save several locations into a plist file for later use,
after a bit of googling I discovered that an array of CLLocation per se cannot be saved,
so I was wondering about a way to do it.
I was thinking about a couple of classes to "serialize"/"deserilize" a single CLLocation object into an NSDictionary and then store an array of those NSDictionaries into the plist file, but I was wondering if there could be a better/smarter/reliable way to achieve that.
thanks in advance.
EDIT:
this is the function I use to save the data in the plist (the c_propertyName takes the code from the answer)
- (void) addLocation {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"/Locations.plist"];
NSArray *keys = [curLocation c_propertyNames];
NSDictionary *dict = [curLocation dictionaryWithValuesForKeys:keys];
[dict writeToFile: path atomically:YES];
}
EDIT 2 — SOLUTIONS:
Ok, I've figured all out. right below, I've posted a two-optioned solution to my own question.
It's quite easy with KVC.
Here's method of NSObject category to get property names (requires <objc/runtime.h>)
- (NSArray *)c_propertyNames {
Class class = [self class];
u_int count = 0;
objc_property_t *properties = class_copyPropertyList(class, &count);
if (count <= 0) {
return nil;
}
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, count)];
NSMutableSet *retVal = [NSMutableSet setWithCapacity:count];
[set enumerateIndexesWithOptions:NSEnumerationConcurrent
usingBlock:^(NSUInteger idx, BOOL *stop) {
const char *propName = property_getName(properties[idx]);
NSString *name = [NSString stringWithUTF8String:propName];
[retVal addObject:name];
}];
return [retVal allObjects];
}
then use it like this :
NSArray *keys = [yourLocation c_propertyNames];
NSDictionary *dict = [yourLocation dictionaryWithValuesForKeys:keys];
then save that dictionary.
I like solution 2 but serialization can be simpler if all one is trying to do is write straight to a file.
[NSKeyedArchiver archiveRootObject:arrayOfLocations toFile:path];
after some hours of search I've figured out the entire scenario.
Here you got a couple of solutions; the first is the more "dirty", because it's the first I've came up with, while the second is the more elegant. Anyway, I'll leave'em both because maybe they could both come in handy to somebody.
S O L U T I O N — 1
Thanks to the help of mit3z I could put together the pieces to figure out a solution.
as he points out, you can implement this method into a category on the NSObject:
- (NSArray *)c_propertyNames;
( look at his response for this part's code and further more details about it )
this gives me the liberty to do such thing:
- (void) addLocation {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"/Locations.plist"];
NSArray *keys = [curLocation c_propertyNames]; // retrieve all the keys for this obj
NSDictionary *values = [self.curLocation dictionaryWithValuesForKeys:keys];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for(NSString *key in keys) {
NSString *aaa = [NSString stringWithFormat:#"%#", (NSString *)[values valueForKey:key]];
[dict setValue:aaa forKey:key];
}
[dict writeToFile:path atomically:YES];
}
the superdumb for loop is needed to convert all the data in the NSDictionary into NSStrings so that they can be written into the plist file without troubles, if you just make the dictionary and then you attempt to save it right away, you wan't succeed.
In this way I can have all the CLLocation obj "serialized" into a dict and then written into a plist file.
S O L U T I O N — 2
I came up with a really easiest (and more elegant) way to do so: using the NSCoding.
Because of the fact (that I realized that)the CLLocation datatype conforms NSCoding, you can invoke the data archiver via NSKeyedArchiver to get a blob describing your array and then store it right to the plist, like that:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"/Locations.plist"];
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
[data setValue:[NSKeyedArchiver archivedDataWithRootObject:arrayOfLocations] forKey:#"LocationList"];
[data writeToFile:path atomically:YES];
[data release];
and voila'. simple as that! :)
based on the same principles you can easily get back your data, via NSKeyUnarchiver:
self.arrayOfLocations = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData: (NSData *)[dict objectForKey:#"LocationList"]]];

Parsed TouchXML XML file crashes when reading NSString

I'm able to successfully parse the contents of a XML file using TouchXML, but when I try to read an individual NSString, from the NSMutableArray that stores the parsed content, the iPhone app crashes.
My NSLog shows me that the file has been parse as it should, giving this output:
(
{
href = "mms://a19349.l412964549958.c41245496.f.lm.akamaistream.net/D/194359/4125596/v0001/reflector:49944";
},
{
href = "mms://a4322.l4129624350471.c414645296.a.lm.akamaistream.net/D/473432/4129566/v0001/reflector:546441";
} )
Here is the code I'm using to do the parsing:
NSMutableArray *res = [[NSMutableArray alloc] init];
.... Parsing happens here ....
Then I try to retrieve the string from the NSMutableArray, using this code (and the app crashes when trying to read this line of code, posted below NSMutableString *string1 = [NSMutableString stringWithString:url];
NSString *url = [[NSString alloc] init];
url = [res objectAtIndex:0];
NSMutableString *string1 = [NSMutableString stringWithString:url];
[string1 deleteCharactersInRange: [string1 rangeOfString: #"href = "]];
[string1 deleteCharactersInRange: [string1 rangeOfString: #";"]];
NSLog(#"Clean URL: %#", string1);
Please, how can I solve this problem? Thank you!
TouchXML returns you an array of NSDictionaries. In order to extract string you need to take value from this NSDictionary:
NSString *url = [[res objectAtIndex:0] objectForKey:#"href"];