I'm using very tricky fighting methods :) to make a string like Fi?le*/ Name
safe for using as a file name like File_Name
.
I'm sure there is a cocoa way to convert it. And I'm sure the best place to ask is here :)
Thank you!
I'm using very tricky fighting methods :) to make a string like Fi?le*/ Name
safe for using as a file name like File_Name
.
I'm sure there is a cocoa way to convert it. And I'm sure the best place to ask is here :)
Thank you!
Unless you're explicitly running the shell or implicitly running the shell by using a function such as popen
or system
, there's no reason to escape anything but the pathname separator.
You may also want to enforce that the filename does not begin with a full stop (which would cause Finder to hide the file) and probably should also enforce that it is not empty and is fewer than NAME_MAX
characters* long.
*syslimits.h
says bytes, but if you go through File Manager, it's characters. I'm not sure which is right for Cocoa.
This will remove all invalid characters anywhere in the filename based on Ismail's invalid character set (I have not verified how complete his set is).
- (NSString *)_sanitizeFileNameString:(NSString *)fileName {
NSCharacterSet* illegalFileNameCharacters = [NSCharacterSet characterSetWithCharactersInString:@"/\\?%*|\"<>"];
return [[fileName componentsSeparatedByCharactersInSet:illegalFileNameCharacters] componentsJoinedByString:@""];
}
Credit goes to Peter N Lewis for the idea to use componentsSeparatedByCharactersInSet:
NSString - Convert to pure alphabet only (i.e. remove accents+punctuation)
Solution in Swift 4
extension String {
var sanitizedFileName: String {
return components(separatedBy: .init(charactersIn: "/\:\?%*|\"<>")).joined()
}
}
Usage:
"https://myurl.com".sanitizedFileName // = httpsmyurl.com
NSURL *fileURL = [NSURL fileURLWithPath:yourFilePath isDirectory:NO];
if (fileURL) {
NSError *error;
fileURL = [NSURL URLByResolvingAliasFileAtURL:fileURL options:(NSURLBookmarkResolutionWithoutUI | NSURLBookmarkResolutionWithoutMounting) error:&error];
}
/Users/XXX/Desktop/~!@#$%^&*()_+`-={}|"<>?[]\;',.: {}<>:^ .png
file:///Users/johnny/Desktop/~!@%23$%25%5E&*()_+%60-=%7B%7D%7C%22%3C%3E%3F%5B%5D%5C%3B',.:%20%20%7B%7D%3C%3E%5C:%5E%20.png
And of course there's got to be a swift2 guy with an arbitrary hate list (stolen from other answers). That guy is me:
func sanitizedString(string : String) -> String {
// put anything you dislike in that set ;-)
let invalidFsChars = NSCharacterSet(charactersInString: "/* <>?%|")
let components = string.componentsSeparatedByCharactersInSet(invalidFsChars)
return components.joinWithSeparator("")
}
I iterated on johnboiles's answer, converting to Swift, and writing it as an extension:
extension String {
var stringForFilePath: String {
// characterSet contains all illegal characters on OS X and Windows
let characterSet = NSCharacterSet(charactersInString: "\"\\/?<>:*|")
// replace "-" with character of choice
return componentsSeparatedByCharactersInSet(characterSet).joinWithSeparator("-")
}
}
Illegal character set referenced from here.
According to wikipedia, the most common characters that should be excluded from filenames are:
/\?%*|"<>
http://en.wikipedia.org/wiki/Filename
Given that, and since the invertedSet operation in the alternate solution can be intensive, to me the below is a cleaner approach:
NSCharacterSet *invalidFsChars = [NSCharacterSet characterSetWithCharactersInString:@"/\\?%*|\"<>"];
NSString *scrubbed = [originalStr stringByTrimmingCharactersInSet:invalidFsChars];
This way you can still allow filenames that have dash, etc.