How to make an NSString path (file name) safe

自古美人都是妖i 提交于 2019-12-02 17:53:07

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.

johnboiles

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];

}

Before Transfer:

/Users/XXX/Desktop/~!@#$%^&*()_+`-={}|"<>?[]\;',.: {}<>:^ .png

After Transfer:

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

SeanR

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.

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("")
}

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!