我正在寻找一种方法来确保字符串可以用作 iOS 下的文件名。我目前处于删除不兼容字符的代码部分。我想知道我这样做是否正确。
NSString *filename = @"A file name";
fileName = [fileName stringByTrimmingCharactersInSet: [NSCharacterSet controlCharacterSet]];
fileName = [fileName stringByTrimmingCharactersInSet: [NSCharacterSet newlineCharacterSet]];
我还想知道是否已经有一种方法可以验证字符串作为文件名。
谢谢您的建议!
使用正则表达式:
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:)
一次。
var invalidCharacters = CharacterSet(charactersIn: ":/")
invalidCharacters.formUnion(.newlines)
invalidCharacters.formUnion(.illegalCharacters)
invalidCharacters.formUnion(.controlCharacters)
let newFilename = originalFilename
.components(separatedBy: invalidCharacters)
.joined(separator: "")
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//\r\r".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:@"-"];
享受吧!
由 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.isEmpty }
// Put the components back together and join them with a "-".
let result = cleanedUpComponentsWithoutBlanks.joined(separator: "_")
我也想删除表情符号,在 Windows 中
\
也是无效字符。所以我还添加了 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)