【问题标题】:How to make an NSString path (file name) safe如何使 NSString 路径(文件名)安全
【发布时间】:2010-11-19 21:00:45
【问题描述】:

我正在使用非常棘手的战斗方法:) 使Fi?le*/ Name 之类的字符串可以安全地用作File_Name 之类的文件名。 我敢肯定有一种可可的方式来转换它。我敢肯定最好的地方就是这里 :)

谢谢!

【问题讨论】:

  • 搜索 NSScanner。这个想法是去除无效字符,或者只在结果中包含字母数字字符。
  • 还有方便的方法stringByTrimmingCharactersInSet:.
  • stringByTrimmingCharactersInSet 仅从字符串的开头或结尾删除字符,而不是从字符串中的任何位置(因此在这里不合适)

标签: cocoa string nsstring filenames


【解决方案1】:

这将根据 Ismail 的无效字符集删除文件名中任何位置的所有无效字符(我尚未验证他的集有多完整)。

- (NSString *)_sanitizeFileNameString:(NSString *)fileName {
    NSCharacterSet* illegalFileNameCharacters = [NSCharacterSet characterSetWithCharactersInString:@"/\\?%*|\"<>"];
    return [[fileName componentsSeparatedByCharactersInSet:illegalFileNameCharacters] componentsJoinedByString:@""];
}

感谢 Peter N Lewis 提出使用 componentsSeparatedByCharactersInSet 的想法:
NSString - Convert to pure alphabet only (i.e. remove accents+punctuation)

【讨论】:

  • 对于 Mac OS X 10.5 及更高版本,有一个 -stringByReplacingCharactersInRange:withString: 方法。
  • 在 OSX 上文件名的唯一非法字符是 /:
  • @keegan3d 可以提供链接吗?
  • 仅供参考,至少从优胜美地开始,我可以在 OS X 文件名中使用/: 仍然无效。 illegalFileNameCharacters 中的所有字符在 OSX 中似乎都是合法的
  • touch '\?%*|"&lt;&gt;:' 在 MacOS 和 Linux 上运行良好,因此除了 / 之外,这些答案中的所有字符都是非法的。
【解决方案2】:

除非您显式运行 shell 或使用诸如 popensystem 之类的函数隐式运行 shell,否则除了路径名分隔符之外没有理由转义任何内容。

您可能还想强制文件名不以句号开头(这会导致 Finder 隐藏文件),并且可能还应该强制文件名不为空且长度少于 NAME_MAX 个字符*。

*syslimits.h 表示字节,但如果你通过文件管理器,它是字符。我不确定哪个适合 Cocoa。

【讨论】:

  • 正确,但我也不鼓励文件名在末尾带有句号
【解决方案3】:

Swift 4 中的解决方案

extension String {
    var sanitizedFileName: String {
        return components(separatedBy: .init(charactersIn: "/\:\?%*|\"<>")).joined()
    }
}

用法:

"https://myurl.com".sanitizedFileName // = httpsmyurl.com

【讨论】:

  • 有趣,我只报告 \ before ?在 Xcode 9.2 中导致 4 个错误。
  • @Cue 我认为这是在 9.0 上实现的,ymmv。您可能需要删除斜线或转义它
【解决方案4】:
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

【讨论】:

    【解决方案5】:

    我在 johnboiles's answer 上进行了迭代,转换为 Swift,并将其编写为扩展:

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

    here引用的非法字符集。

    【讨论】:

      【解决方案6】:

      当然,必须有一个 swift2 的家伙,具有任意性 仇恨列表(从其他答案中窃取)。那个人就是我:

      func sanitizedString(string : String) -> String {
          // put anything you dislike in that set ;-)
          let invalidFsChars = NSCharacterSet(charactersInString: "/* <>?%|")
          let components = string.componentsSeparatedByCharactersInSet(invalidFsChars)
          return components.joinWithSeparator("")
      }
      

      【讨论】:

        【解决方案7】:

        根据维基百科,应该从文件名中排除的最常见字符是:

        /\?%*|"

        http://en.wikipedia.org/wiki/Filename

        鉴于此,并且由于替代解决方案中的倒置集操作可能很密集,对我来说,以下是一种更简洁的方法:

        NSCharacterSet *invalidFsChars = [NSCharacterSet characterSetWithCharactersInString:@"/\\?%*|\"<>"];
        NSString *scrubbed = [originalStr stringByTrimmingCharactersInSet:invalidFsChars];
        

        这样你仍然可以允许包含破折号等的文件名。

        【讨论】:

        • 使用stringByTrimmingCharactersInSet的问题是它只删除文件名开头和结尾的无效字符。
        • 冒号“:”也不是 Windows 系统的合法字符,如果您正在访问 SMB 挂载的文件系统,这可能是个问题。
        猜你喜欢
        • 1970-01-01
        • 2015-11-17
        • 2010-12-19
        • 1970-01-01
        • 2013-08-12
        • 2013-12-22
        • 1970-01-01
        • 1970-01-01
        • 2011-04-28
        相关资源
        最近更新 更多