>我正在寻找一种方法来确保字符串可以在iOS下用作文件名。我目前在删除不兼容字符的代码部分。我想知道我做得对不对。
NSString *filename = @"A file name";
fileName = [fileName stringByTrimmingCharactersInSet: [NSCharacterSet controlCharacterSet]];
fileName = [fileName stringByTrimmingCharactersInSet: [NSCharacterSet newlineCharacterSet]];
我还想知道是否已经有一种方法可以将字符串验证为文件名。
谢谢你的建议!
使用 RegEx:
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-zA-Z0-9_]+" options:0 error:nil];
filename = [regex stringByReplacingMatchesInString:filename options:0 range:NSMakeRange(0, filename.length) withTemplate:@"-"];
我发现这更干净,可能性能更高。这是基于Angel Naydenov的解决方案,但首先使用所有无效字符构造字符集,然后只调用components(separatedBy:)
一次。
Swift 3 & 4
var invalidCharacters = CharacterSet(charactersIn: ":/")
invalidCharacters.formUnion(.newlines)
invalidCharacters.formUnion(.illegalCharacters)
invalidCharacters.formUnion(.controlCharacters)
let newFilename = originalFilename
.components(separatedBy: invalidCharacters)
.joined(separator: "")
斯威夫特 2
let invalidCharacters = NSMutableCharacterSet(charactersInString: ":/")
invalidCharacters.formUnionWithCharacterSet(NSCharacterSet.newlineCharacterSet())
invalidCharacters.formUnionWithCharacterSet(NSCharacterSet.illegalCharacterSet())
invalidCharacters.formUnionWithCharacterSet(NSCharacterSet.controlCharacterSet())
let filename = originalFilename
.componentsSeparatedByCharactersInSet(invalidCharacters)
.joinWithSeparator("")
首先,你使用了错误的方法。修剪字符串只会删除字符串开头和结尾的字符。
您正在寻找的内容更像是:
fileName = [fileName stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
但是,这是一个次优的解决方案,因为您必须对要排除的每个字符执行此操作,因此您可能希望继续查找或编写自己的方法来操作字符串。
iOS是基于UNIX的,因此我想它几乎支持文件名中的任何字符。UNIX 允许使用空格、<、>、|、\、:、(、)、&、;,以及通配符,如 ?和 *,使用 \ 符号引用或转义。但是,我不会在文件名中使用任何这些字符。事实上,我会将文件名中的字符限制为"a"-"z"、"0"-"9"、"_"和"."。
由于我在此问题中没有看到包含允许字符的列表,因此该问题想要包含此类字符的列表,因此我正在添加有关此主题的更多详细信息。
首先,我们需要知道iOS设备使用的文件系统是什么。使用多个在线资源,这似乎是HFSX,它是HFS+区分大小写的版本。并在此处包含一个链接以供参考:https://apple.stackexchange.com/questions/83671/what-filesystem-does-ios-use
现在我们知道文件系统是什么,我们可以查找不允许的字符。这些似乎是:结肠(:)和斜杠 (/)。以下是供参考的链接:http://www.comentum.com/File-Systems-HFS-FAT-UFS.html
有了这些信息以及其他人在此线程中编写的内容,我个人更喜欢从文件名中删除不允许的字符,这是以下 Swift 代码:
filename = "-".join(filename.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()))
filename = "-".join(filename.componentsSeparatedByCharactersInSet(NSCharacterSet.illegalCharacterSet()))
filename = "-".join(filename.componentsSeparatedByCharactersInSet(NSCharacterSet.controlCharacterSet()))
filename = "-".join(filename.componentsSeparatedByString(":"))
filename = "-".join(filename.componentsSeparatedByString("/"))
我不喜欢正则表达式方法的原因是它对我来说似乎太严格了。我不想将我的用户限制为仅拉丁字符。他们可能也希望使用一些中文,西里尔文或其他他们喜欢的东西。
祝您编码愉快!
此字符串扩展名 (Swift 4.2) 将有助于将无效的 iOS 文件名转换为有效的 iOS 文件名。
extension String {
func convertToValidFileName() -> String {
let invalidFileNameCharactersRegex = "[^a-zA-Z0-9_]+"
let fullRange = startIndex..<endIndex
let validName = replacingOccurrences(of: invalidFileNameCharactersRegex,
with: "-",
options: .regularExpression,
range: fullRange)
return validName
}
}
例如
"name.name?/!!23$$@1asd".convertToValudFileName() // "name-name-23-1asd"
"!Hello.312,^%-0//rr".convertToValidFileName() // "-Hello-312-0-"
"/foo/bar/pop?soda=yes|please".convertToValidFileName() // "-foo-bar-pop-soda-yes-please"
我不得不使用文件名包含基本字母数字字符以外的其他字符的文件名在本地保存远程文件。我使用以下方法来去除潜在的无效字符,确保在使用 URLWithString 生成 NSURL 时它是文件系统的有效文件名:
filename = [[filename componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:@"" ];
filename = [[filename componentsSeparatedByCharactersInSet:[NSCharacterSet illegalCharacterSet]] componentsJoinedByString:@"" ];
filename = [[filename componentsSeparatedByCharactersInSet:[NSCharacterSet symbolCharacterSet]] componentsJoinedByString:@"" ];
fileURLString = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
fileURL = [NSURL URLWithString:fileURLString];
您可能还希望首先使用以下方法测试碰撞错误:
[[NSFileManager defaultManager] fileExistsAtPath:[fileURL absoluteString]]
我对这个解决方案非常满意:
NSString *testString = @"This*is::/legal.😀,?縦書き 123";
NSString *result = [[[testString componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"length > 0"]] componentsJoinedByString:@"-"];
输出:
"This-is-legal-縦書き-123"
这是什么巫术?
让我把它分成多行,这样就清楚发生了什么:
NSString *testString = @"This*is::/legal.😀,?縦書き 123";
// Get a character set for everything that's NOT alphanumeric.
NSCharacterSet *nonAlphanumericCharacterSet = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
// Split the string on each non-alphanumeric character, thus removing them.
NSArray *cleanedUpComponentsWithBlanks = [testString componentsSeparatedByCharactersInSet:nonAlphanumericCharacterSet];
// Filter out empty strings ("length" is a KVO-compliant property that the predicate can call on each NSString in the array).
NSArray *cleanedUpComponentsWithoutBlanks = [cleanedUpComponentsWithBlanks filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"length > 0"]];
// Put the components back together and join them with a "-".
NSString *result = [cleanedUpComponentsWithoutBlanks componentsJoinedByString:@"-"];
享受!
斯威夫特 4 版本
由 john-pang 于 2021-09-01 添加,带有 Swift 版本:
let testString = "This*is::/legal.😀,?縦書き 123"
// Get a character set for everything that's NOT alphanumeric.
let nonAlphanumericCharacterSet = CharacterSet.alphanumerics.inverted
// Split the string on each non-alphanumeric character, thus removing them.
let cleanedUpComponentsWithBlanks = testString.components(separatedBy: nonAlphanumericCharacterSet)
// Filter out empty strings ("length" is a KVO-compliant property that the predicate can call on each NSString in the array).
let cleanedUpComponentsWithoutBlanks = cleanedUpComponentsWithBlanks.filter { $0.length > 0 }
// Put the components back together and join them with a "-".
let result = cleanedUpComponentsWithoutBlanks.joined(separator: "_")
Swift 5 扩展:
我也想删除表情符号,在窗口中也是一个无效字符。所以我也添加了
symbols
字符集和反斜杠。
extension String {
var validFilename: String {
let invalidCharsets = CharacterSet(charactersIn: ":/\")
.union(.illegalCharacters)
.union(.controlCharacters)
.union(.symbols)
.union(.newlines)
return self.components(separatedBy: invalidCharsets).joined()
}
}
我想出了以下解决方案。到目前为止效果很好。
import Foundation
extension String {
func removeUnsupportedCharactersForFileName() -> String {
var cleanString = self
["?", "/", "\", "*"].forEach {
cleanString = cleanString.replacingOccurrences(of: $0, with: "-")
}
return cleanString
}
}
let a = "***???foo.png"
let validString = a.removeUnsupportedCharactersForFileName()
基于Marian Answers,这里有一个字符串扩展,用于删除任何不需要的字符。
extension String {
func stripCharacters() -> String {
var invalidCharacters = CharacterSet(charactersIn: ":/")
invalidCharacters.formUnion(.newlines)
invalidCharacters.formUnion(.illegalCharacters)
invalidCharacters.formUnion(.controlCharacters)
let newString = self
.components(separatedBy: invalidCharacters)
.joined(separator: "_")
return newString
}
}
Example:
let fileName = "Man(lop23/45"
let newFileName = fileName.stripCharacters()
print(newFileName)