Split NSString in exactly two pieces - objective-c

Which is the optimum way to split an NSString in two pieces? My idea was to split a filename in two parts the filename itself and the extension. I would like to know which could be the most simple one.

NSStringoffers some of its own implementations that will do exactly what you want for filenames and paths.
See https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/#//apple_ref/doc/uid/20000154-SW38 and there for example lastPathComponentor pathExtension.
[yourFilePath lastPathComponent] gives you the filename of a given path. [yourFilePath pathExtension] gives you the extension. Note this works for NSURL as well, but expects a valid path or URL respectively.

NSString *filename = [sFilename lastPathComponent]; // this will give you pure filename if it's a path already
NSArray *filenameParts = [filename componentsSeparatedByString:#"."];
if ([filenameParts count] == 2) {
NSString *file = [filenameParts objectAtIndex:0];
NSString *fileExtension = [filenameParts objectAtIndex:1];
...
}

Related

Check if it is possible to break a string into chunks?

I have this code who chunks a string existing inside a NSString into a NSMutableArray:
NSString *string = #"one/two/tree";
NSMutableArray *parts = [[string componentsSeparatedByString:#"/"] mutableCopy];
NSLog(#"%#-%#-%#",parts[0],parts[1],parts[2]);
This command works perfectly but if the NSString is not obeying this pattern (not have the symbol '/' within the string), the app will crash.
How can I check if it is possible to break the NSString, preventing the app does not crash?
Just check parts.count if you don't have / in your string (or only one), you won't get three elements.
NSString *string = #"one/two/tree";
NSMutableArray *parts = [[string componentsSeparatedByString:#"/"] mutableCopy];
if(parts.count >= 3) {
NSLog(#"%#-%#-%#",parts[0],parts[1],parts[2]);
}
else {
NSLog(#"Not found");
}
From the docs:
If list has no separators—for example, "Karin"—the array contains the string itself, in this case { #"Karin" }.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/componentsSeparatedByString:
You might be better off using the "opposite" function to put it back together...
NSString *string = #"one/two/three";
NSArray *parts = [string componentsSeparatedByString:#"/"];
NSString *newString = [parts componentsJoinedByString:#"-"];
// newString = #"one-two-three"
This will take the original string. Split it apart and then put it back together no matter how many parts there are.

String search in objective-c

Given a string like this:
http://files.domain.com/8aa55fc4-3015-400e-80f5-390997b43cf9/c07cb0d2-b7d7-4bfd-b0c3-6f43571e3c29-MyFile.jpg
I need to just locate the string "MyFile", and also tell what kind of image it is (.jpg or .png). How can I accomplish this?
The only thing I can think of is to search backward for the first four characters to get the file extension, then keep searching backward until I find the first hyphen, and assume the file name itself doesn't have any hyphens. But I don't know how to do that. Is there a better way?
Use NSRegularExpression to search for the file name. The search pattern really depends on what you know about the file name. If the "random" numbers and characters before MyFile has a known format, you could take that into account. My proposal below assumes that the file name doesn't contain any minus signs.
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"-([:alnum:]*)\\.(jpg|png)$"
options:NSRegularExpressionSearch
error:nil];
// Get the match between the first brackets.
NSTextCheckingResult *match = [regex firstMatchInString:string options:0
range:NSMakeRange(0, [string length])];
NSRange matchRange = [match rangeAtIndex:1];
NSString *fileName = [string substringWithRange:matchRange];
NSLog(#"Filename: %#", fileName);
// Get the extension with a simple NSString method.
NSString *extension = [string pathExtension];
NSLog(#"Extension: %#", extension);
[myString lastPathComponent] will get the filename.
[myString pathExtension] will get the extension.
To get the suffix of the filename, I think you'll have to roll your own parse. Is it always the string after the last dash and before the extension?
If so, here's an idea:
- (NSString *)lastLittleBitOfTheFilenameFrom:(NSString *)filename {
NSInteger fnStart = [filename rangeOfString:#"-" options:NSBackwardsSearch].location + 1;
NSInteger fnEnd = [filename rangeOfString:#"." options:NSBackwardsSearch].location;
// might need some error checks here depending on what you expect in the original url
NSInteger length = fnEnd - fnStart;
return [filename substringWithRange:NSMakeRange(fnStart, length)];
}
Or, thanks to #Chuck ...
// even more sensitive to unexpected input, but nice and tiny ...
- (NSString *)lastLittleBitOfTheFilenameFrom:(NSString *)filename {
NSString *nameExt = [[filename componentsSeparatedByString:#"-"] lastObject];
return [[nameExt componentsSeparatedByString:#"."] objectAtIndex:0];
}
If you have the string in an NSString object, or create it from that string, you may use the rangeOfString method to acomplish both.
See https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html for more details.

What is the best way to cut path from NSString?

I am new in Cocoa. I have NSString . that looks like this
Attribute: OtherAttributte: /users/user/etc...
What is the best way to cut off and store separately that Path?
Thanks.
You can use rangeOfString and substringFromIndex.
NSString *path = #"Attribute: OtherAttributte: /users/user/etc";
NSRange x = [path rangeOfString:#"/"];
NSString *final = [path substringFromIndex:x.location];
This will work if your path starts with #"/".
Use rangeOfString:#"/" to find the location of the first forward slash, and then substringFromIndex: to extract it.
First approach:
NSString *path = #"tmp/scratch";
NSArray *pathComponents = [path pathComponents];
Second approach:
NSString *path = #" /users/user/etc";
NSArray *parts = [list componentsSeparatedByString:#"/"];
I would use componentsSeparatedByString: which is a method of NSString.
I'm not fully sure whether you're asking how to get the path from the string of arguments, or how to get a part of the path, so I'll outline how I'd do both in separate steps below:
NSString *args = #"attribute1: attribute2: /users/user/etc";
NSString *path = [[args componentsSeparatedByString:#":"] last];
NSArray *pathComponents = [path pathComponents];
Obviously this relies on the path being the value of the final argument, but you could use a different means finding the path in the array produced from args.
Details of NSString methods can be found here, and NSArray methods here.

NSString: changing a filename but not the extension

Times like this and my Objective-C noobness shows. :-/
So, the more I work on a routine to do this, the more complex it's becoming, and I'm wondering if there isn't just a simple method to change the name of a filename in a path. Basically, I want to change #"/some/path/abc.txt to #"/some/path/xyz.txt -- replacing the filename portion but not changing the path or extension.
Thanks!
Try the following:
NSString* initPath = ...
NSString *newPath = [[NSString stringWithFormat:#"%#/%#",
[initPath stringByDeletingLastPathComponent], newFileName]
stringByAppendingPathExtension:[initPath pathExtension]];
What Vladimir said, just broken down more to make it a little easier to read:
NSString *pathToFile = #"/Path/To/File.txt";
NSString *oldFileName = [pathToFile lastPathComponent];
NSString *newFileName = [#"Document" stringByAppendingPathExtension:[oldFileName pathExtension];
NSString *newPathToFile = [pathToFile stringByDeletingLastPathComponent];
[newPathToFile stringByAppendingString:newFileName];
Take a look at the "Working With Paths" section of the NSString docs. In particular, lastPathComponent, pathExtension and stringByDeletingPathExtension: should do what you want.
You can try something like this:
NSRange slashRange = [myString rangeOfString:#"\\" options:NSBackwardsSearch];
NSRange periodRange = [myString rangeOfString:#"." options:NSBackwardsSearch];
NSString *newString = [myString stringByReplacingCharactersInRange:NSMakeRange(slashRange.location, periodRange.location) withString:#"replacement-string-here"];
What this code does is it gets the location of the \ and . characters and performs a backwards search so that it returns the last occurrence of it in the string.
Then, it creates a new range based on those previous ranges and replaces the contents in that range with stringByReplacingCharactersInRange:.
Try this:
NSString* path = [startString stringByDeletingLastPathComponent];
NSString* extension = [startString pathExtension];
NSString* replacementFileName = [#"foo" stringByAppendingPathExtension: extension];
NSString result = [path stringByAppendingPathComponent: replacementFileName];

How do I convert an NSString into something I can use with FSCreateDirectoryUnicode?

I'm new to Mac and Objective-C, so I may be barking up the wrong tree here and quite possibly there are better ways of doing this.
I have tried the code below and it doesn't seem right. It seems I don't get the correct length in the call to FSCreateDirectoryUnicode. What is the simplest way to accomplish this?
NSString *theString = #"MyFolderName";
NSData *unicode = [theString dataUsingEncoding:NSUnicodeStringEncoding allowLossyConversion:NO];
FSCreateDirectoryUnicode(&aFolderFSRef, [theString length], [unicode bytes], kFSCatInfoNone, NULL, &newFolderFSRef, NULL, NULL);
There are a couple of issues with your raw string data. But the easiest way to do it in Cocoa is:
NSString *theString = #"MyFolderName";
NSString* path = [NSHomeDirectory() stringByAppendingPathComponent:theString];
[[NSFileManager defaultManager] createDirectoryAtPath:path
attributes:nil];
You did use an FSRef to specify the path to where the directory was created. My example uses the home directory instead. If you really have to use the directory in the FSRef and do not know the path to it, it might be easier to use the FSCreateDirectoryUnicode function:
Edit: changed code to use correct encoding.
NSString *theString = #"MyFolderName";
const UniChar* name = (const UniChar*)[theString cStringUsingEncoding:NSUnicodeStringEncoding];
FSCreateDirectoryUnicode(&aFolderFSRef, [theString length], name, kFSCatInfoNone, NULL, &newFolderFSRef, NULL, NULL);
The only thing that was broken in the original code, was that dataUsingEncoding returns the external representation of the string. That means that the data contains a unicode byte order mark at the beginning, which FSCreateDirectoryUnicode does not want.
Your code looks OK. I would use [unicode length]/2 as the length, although that should be equal to [theString length] in all (or at least almost all) cases.
Alternatively, you can use Nathan Day's NDAlias NSString+NDCarbonUtilities category
+ (NSString *)stringWithFSRef:(const FSRef *)aFSRef
{
NSString * thePath = nil;
CFURLRef theURL = CFURLCreateFromFSRef( kCFAllocatorDefault, aFSRef );
if ( theURL )
{
thePath = [(NSURL *)theURL path];
CFRelease ( theURL );
}
return thePath;
}
to get the path for your FSRef and then Nikolai's solution:
NSString* aFolderPath = [NSString stringWithFSRef:aFolderFSRef];
NSString* path = [aFolderPath stringByAppendingPathComponent:theString];
[[FSFileManager defaultManager] createDirectoryAtPath:path attributes:nil];