iOS 文件名中允许使用哪些字符?

问题描述 投票:0回答:10

我正在寻找一种方法来确保字符串可以用作 iOS 下的文件名。我目前处于删除不兼容字符的代码部分。我想知道我这样做是否正确。

NSString *filename = @"A file name";
fileName = [fileName stringByTrimmingCharactersInSet: [NSCharacterSet controlCharacterSet]];
fileName = [fileName stringByTrimmingCharactersInSet: [NSCharacterSet newlineCharacterSet]];

我还想知道是否已经有一种方法可以验证字符串作为文件名。

谢谢您的建议!

ios file filenames character-encoding nsfilemanager
10个回答
32
投票

使用正则表达式:

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-zA-Z0-9_]+" options:0 error:nil];
filename = [regex stringByReplacingMatchesInString:filename options:0 range:NSMakeRange(0, filename.length) withTemplate:@"-"];

22
投票

我发现这更干净,而且性能可能更高。这是基于 Angel Naydenov 的解决方案,但首先使用所有无效字符构建字符集,然后仅调用

components(separatedBy:)
一次。

斯威夫特 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("")

12
投票

首先,你使用的方法是错误的。修剪字符串只会删除字符串开头和结尾的字符。

您正在寻找的更像是:

fileName = [fileName stringByReplacingOccurrencesOfString:@"/" withString:@"_"];

但是,这是一个次优的解决方案,因为您必须对要排除的每个字符执行此操作,所以也许您想继续查找或编写自己的操作字符串的方法。

iOS 是基于 UNIX 的,因此我认为它支持文件名中的几乎所有字符。 UNIX 允许使用空格、<, >、|、\、:、(、)、&、; 以及通配符,例如 ?和 *,使用 \ 符号进行引用或转义。但是我不会在文件名中使用任何这些字符。事实上,我会将文件名中的字符限制为“a”-“z”、“0”-“9”、“_”和“.”。


10
投票

由于我在这个问题中没有看到包含允许的字符的列表,但问题想要一个包含此类字符的列表,因此我将添加有关此主题的更多详细信息。

首先我们需要知道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("/"))

我不喜欢正则表达式方法的原因是它对我来说似乎限制太多。我不想将我的用户限制为只能使用拉丁字符。他们可能还希望使用一些中文、西里尔字母或任何他们喜欢的其他字母。

编码快乐!


10
投票

此字符串扩展(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"

9
投票

我必须在本地保存远程文件,文件名中包含除基本字母数字字符之外的其他字符。我使用下面的方法去除潜在的无效字符,确保在使用 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]]

3
投票

我对这个解决方案非常满意:

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:@"-"];

享受吧!

Swift 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.isEmpty }
// Put the components back together and join them with a "-".
let result = cleanedUpComponentsWithoutBlanks.joined(separator: "_")

2
投票

Swift 5 扩展:

我也想删除表情符号,在 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()
    }
}

1
投票

我想出了以下解决方案。到目前为止效果很好。

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

1
投票

基于 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)
© www.soinside.com 2019 - 2024. All rights reserved.