Wenn Sie den Namen einer Datei im Bundle erhalten, möchte ich die Datei in meine Swift-App laden. Also muss ich diese Methode verwenden:
let soundURL = NSBundle.mainBundle().URLForResource(fname, withExtension: ext)
Aus irgendeinem Grund benötigt die Methode den Dateinamen getrennt von der Dateierweiterung. Gut, es ist leicht genug, die beiden in den meisten Sprachen zu trennen. Aber bis jetzt finde ich es nicht so in Swift.
Also hier ist was ich habe:
var rt: String.Index = fileName.rangeOfString(".", options:NSStringCompareOptions.BackwardsSearch)
var fname: String = fileName .substringToIndex(rt)
var ext = fileName.substringFromIndex(rt)
Wenn ich die Eingabe nicht in die erste Zeile einbeziehe, erhalte ich in den beiden folgenden Zeilen Fehler. Damit bekomme ich einen Fehler in der ersten Zeile:
Cannot convert the expression's type '(UnicodeScalarLiteralConvertible, options: NSStringCompareOptions)' to type 'UnicodeScalarLiteralConvertible'
Wie kann ich den Dateinamen von der Erweiterung trennen? Gibt es eine elegante Möglichkeit, dies zu tun?
Ich war ganz begeistert von Swift, weil es wie eine viel elegantere Sprache schien als Objective C. Aber jetzt finde ich, dass es eine eigene Schwerfälligkeit hat.
Zweiter Versuch: Ich entschied mich für meine eigene Suchmethode:
func rfind(haystack: String, needle: Character) -> Int {
var a = Array(haystack)
for var i = a.count - 1; i >= 0; i-- {
println(a[i])
if a[i] == needle {
println(i)
return i;
}
}
return -1
}
Aber jetzt bekomme ich einen Fehler in der Zeile var rt: String.Index = rfind(fileName, needle: ".")
:
'Int' is not convertible to 'String.Index'
Ohne die Besetzung bekomme ich einen Fehler in den beiden folgenden Zeilen.
Kann mir jemand helfen, diesen Dateinamen und die Erweiterung zu teilen?
Dies ist mit Swift 2, Xcode 7: Wenn Sie den Dateinamen mit der Erweiterung bereits haben, können Sie den vollständigen Dateinamen als ersten Parameter und eine leere Zeichenfolge als zweiten Parameter übergeben:
let soundURL = NSBundle.mainBundle()
.URLForResource("soundfile.ext", withExtension: "")
Alternativ funktioniert auch nil als Erweiterungsparameter.
Wenn Sie eine URL haben und aus irgendeinem Grund den Namen der Datei selbst erhalten möchten, können Sie Folgendes tun:
soundURL.URLByDeletingPathExtension?.lastPathComponent
Swift 4
let soundURL = NSBundle.mainBundle().URLForResource("soundfile.ext", withExtension: "")
soundURL.deletingPathExtension().lastPathComponent
Wie im Kommentar erwähnt, können Sie dies verwenden.
let filename: NSString = "bottom_bar.png"
let pathExtention = filename.pathExtension
let pathPrefix = filename.stringByDeletingPathExtension
Funktioniert mit Swift 3/Swift 4. Hinzufügen dieses Verhaltens zur String
-Klasse:
extension String {
func fileName() -> String {
return NSURL(fileURLWithPath: self).deletingPathExtension?.lastPathComponent ?? ""
}
func fileExtension() -> String {
return NSURL(fileURLWithPath: self).pathExtension ?? ""
}
}
Beispiel:
let file = "image.png"
let fileNameWithoutExtension = file.fileName()
let fileExtension = file.fileExtension()
In Swift 2.1 ist String.pathExtension nicht mehr verfügbar. Stattdessen müssen Sie es durch NSURL-Konvertierung ermitteln:
NSURL(fileURLWithPath: filePath).pathExtension
Diese Lösung funktioniert für alle Instanzen und ist nicht von der manuellen Analyse der Zeichenfolge abhängig.
let path = "/Some/Random/Path/To/This.Strange.File.txt"
let fileName = URL(fileURLWithPath: path).deletingPathExtension().lastPathComponent
Swift.print(fileName)
Die resultierende Ausgabe wird sein
This.Strange.File
In Swift können Sie zu NSString
wechseln, um die Erweiterung schneller zu machen:
extension String {
func getPathExtension() -> String {
return (self as NSString).pathExtension
}
}
In Swift 2.1 scheint dies der aktuelle Weg zu sein:
let filename = fileURL.URLByDeletingPathExtension?.lastPathComponent
let extension = fileURL.pathExtension
Swift 3.x kürzeste native Lösung
let fileName:NSString = "the_file_name.mp3"
let onlyName = fileName.deletingPathExtension
let onlyExt = fileName.pathExtension
Keine Erweiterung oder sonstiges Zeug (habe ich getestet. Basierend auf @gabbler-Lösung für Swift 2)
Strings in Swift können durchaus knifflig sein. Wenn Sie eine reine Swift-Methode wünschen, würde ich Folgendes tun:
find
, um das letzte Vorkommen eines "."
in der reverse
der Zeichenfolge zu findenadvance
, um den korrekten Index des "."
in der Originalzeichenfolge abzurufenString
-Funktion von subscript
, die eine IntervalType
-Anweisung benötigt, um die Zeichenfolgen abzurufenEtwas wie das:
func splitFilename(str: String) -> (name: String, ext: String)? {
if let rDotIdx = find(reverse(str), ".") {
let dotIdx = advance(str.endIndex, -rDotIdx)
let fname = str[str.startIndex..<advance(dotIdx, -1)]
let ext = str[dotIdx..<str.endIndex]
return (fname, ext)
}
return nil
}
Welche würde verwendet werden wie:
let str = "/Users/me/Documents/Something.something/text.txt"
if let split = splitFilename(str) {
println(split.name)
println(split.ext)
}
Welche Ausgänge:
/Users/me/Documents/Something.something/text
txt
Oder verwenden Sie einfach die bereits verfügbaren NSString
-Methoden wie pathExtension
und stringByDeletingPathExtension
.
Versuchen Sie dies für eine einfache Swift 4-Lösung
extension String {
func stripExtension(_ extensionSeperator: Character = ".") -> String {
let selfReversed = self.reversed()
guard let extensionPosition = selfReversed.index(of: extensionSeperator) else { return self }
return String(self[..<self.index(before: (extensionPosition.base.samePosition(in: self)!))])
}
}
print("hello.there.world".stripExtension())
// prints "hello.there"
Das neueste Swift 4.2 funktioniert so:
extension String {
func fileName() -> String {
return URL(fileURLWithPath: self).deletingPathExtension().lastPathComponent
}
func fileExtension() -> String {
return URL(fileURLWithPath: self).pathExtension
}
}
Swift 3.x erweiterte Lösung:
extension String {
func lastPathComponent(withExtension: Bool = true) -> String {
let lpc = self.nsString.lastPathComponent
return withExtension ? lpc : lpc.nsString.deletingPathExtension
}
var nsString: NSString {
return NSString(string: self)
}
}
let path = "/very/long/path/to/filename_v123.456.plist"
let filename = path.lastPathComponent(withExtension: false)
dateiname Konstante enthält jetzt "filename_v123.456"
Swift 5
URL(string: filePath)?.pathExtension
Swift 3.0
let sourcePath = NSURL(string: fnName)?.pathExtension
let pathPrefix = fnName.replacingOccurrences(of: "." + sourcePath!, with: "")
Eine bereinigte Antwort für Swift 4 mit einer Erweiterung von PHAsset
:
import Photos
extension PHAsset {
var originalFilename: String? {
if #available(iOS 9.0, *),
let resource = PHAssetResource.assetResources(for: self).first {
return resource.originalFilename
}
return value(forKey: "filename") as? String
}
}
Wie in XCode angegeben, ist der ursprüngliche Dateiname der Name des Assets zum Zeitpunkt der Erstellung oder des Imports.
Erzeugt einen eindeutigen "Dateinamen" -Formular mit zwei vorherigen Ordnern
func createFileNameFromURL (colorUrl: URL) -> String {
var arrayFolders = colorUrl.pathComponents
// -3 because last element from url is "file name" and 2 previous are folders on server
let indx = arrayFolders.count - 3
var fileName = ""
switch indx{
case 0...:
fileName = arrayFolders[indx] + arrayFolders[indx+1] + arrayFolders[indx+2]
case -1:
fileName = arrayFolders[indx+1] + arrayFolders[indx+2]
case -2:
fileName = arrayFolders[indx+2]
default:
break
}
return fileName
}
Eine bessere Möglichkeit (oder zumindest eine Alternative in Swift 2.0) ist die Verwendung der String pathComponents -Eigenschaft. Dadurch wird der Pfadname in ein String-Array aufgeteilt. z.B
if let pathComponents = filePath.pathComponents {
if let last = pathComponents.last {
print(" The last component is \(last)") // This would be the extension
// Getting the last but one component is a bit harder
// Note the Edge case of a string with no delimiters!
}
}
// Otherwise you're out of luck, this wasn't a path name!
Vielleicht komme ich dafür zu spät, aber eine Lösung, die für mich funktioniert hat und die ich für ziemlich einfach halte, ist die #file
-Compiler-Direktive. Hier ist ein Beispiel, wo ich eine Klasse FixtureManager
habe, die in FixtureManager.Swift
innerhalb des/Tests/MyProjectTests/Fixturesdirectory. This works both in Xcode and with
Swift-Tests definiert ist
import Foundation
final class FixtureManager {
static let fixturesDirectory = URL(fileURLWithPath: #file).deletingLastPathComponent()
func loadFixture(in fixturePath: String) throws -> Data {
return try Data(contentsOf: fixtureUrl(for: fixturePath))
}
func fixtureUrl(for fixturePath: String) -> URL {
return FixtureManager.fixturesDirectory.appendingPathComponent(fixturePath)
}
func save<T: Encodable>(object: T, in fixturePath: String) throws {
let data = try JSONEncoder().encode(object)
try data.write(to: fixtureUrl(for: fixturePath))
}
func loadFixture<T: Decodable>(in fixturePath: String, as decodableType: T.Type) throws -> T {
let data = try loadFixture(in: fixturePath)
return try JSONDecoder().decode(decodableType, from: data)
}
}
Aus irgendeinem Grund wurden sie pathExtension entfernt.
let str = "Hello/this/is/a/filepath/file.ext"
let l = str.componentsSeparatedByString("/")
let file = l.last?.componentsSeparatedByString(".")[0]
let ext = l.last?.componentsSeparatedByString(".")[1]