IOSで文字列をファイル名として使用できるようにする方法を探しています。私は現在、互換性のない文字を削除するコードのセクションにいます。私はそれを正しくやっているかどうか疑問に思っています。
NSString *filename = @"A file name";
fileName = [fileName stringByTrimmingCharactersInSet: [NSCharacterSet controlCharacterSet]];
fileName = [fileName stringByTrimmingCharactersInSet: [NSCharacterSet newlineCharacterSet]];
文字列をファイル名として検証するメソッドがすでにあるかどうかも疑問に思います。
アドバイスありがとうございます!
まず第一に、あなたは間違った方法を使用しています。文字列をトリミングすると、文字列の最初と最後の文字のみが削除されます。
あなたが探しているものはもっと似ています:
fileName = [fileName stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
ただし、これは最適ではない解決策です。除外するすべての文字に対してこれを行う必要があるため、文字列を操作するための独自のメソッドを探し続けたり、記述したりする必要があるかもしれません。
iOSはUNIXベースであるため、ファイル名のほぼすべての文字をサポートしていると思います。 UNIXでは、空白、<、>、|、\、:、(、)、&、;、および?などのワイルドカードを使用できます。および*、\記号を使用して引用符またはエスケープします。ただし、ファイル名にはこれらの文字は使用しません。実際、ファイル名の文字は「a」-「z」、「0」-「9」、「_」、「。」に制限します。
正規表現を使用する:
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-zA-Z0-9_]+" options:0 error:nil];
filename = [regex stringByReplacingMatchesInString:filename options:0 range:NSMakeRange(0, filename.length) withTemplate:@"-"];
これはよりクリーンで、おそらくはるかにパフォーマンスが高いと思います。これはAngelNaydenovのソリューションに基づいていますが、最初にすべての無効な文字を使用して文字セットを作成し、次にcomponents(separatedBy:)
を1回だけ呼び出します。
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("")
基本的な英数字以外の文字を含むファイル名でリモートファイルをローカルに保存する必要がありました。以下の方法を使用して、潜在的な無効な文字を取り除き、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]]
この質問では許可された文字を含むリストは表示されませんでしたが、質問ではそのような文字を含むリストが必要だったため、このトピックについてもう少し詳しく説明します。
まず、iOSデバイスが使用するファイルシステムを知る必要があります。複数のオンラインソースを使用すると、これはHFS +の大文字と小文字を区別するバージョンであるHFSXのようです。そして、参照用にここに1つのリンクを含めます: 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"
私は次の解決策を思いついた。これまでのところうまく機能します。
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)
私はこの解決策にかなり満足しています:
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:@"-"];
楽しい!