Hoe splits ik de bestandsnaam van de bestandsextensie in Swift?

Gezien de naam van een bestand in de bundel, wil ik het bestand in mijn Swift-app laden. Dus ik moet deze methode gebruiken:

let soundURL = NSBundle.mainBundle().URLForResource(fname, withExtension: ext)

Om welke reden dan ook, de methode heeft de bestandsnaam nodig gescheiden van de bestandsextensie. Prima, het is gemakkelijk genoeg om de twee te scheiden in de meeste talen. Maar tot nu toe vind ik het niet zo in Swift.

Dus dit is wat ik heb:

var rt: String.Index = fileName.rangeOfString(".", options:NSStringCompareOptions.BackwardsSearch)
var fname: String = fileName .substringToIndex(rt)
var ext = fileName.substringFromIndex(rt)

Als ik het typen niet op de eerste regel zet, krijg ik fouten op de twee volgende regels. Hiermee krijg ik een foutmelding op de eerste regel:

Cannot convert the expression's type '(UnicodeScalarLiteralConvertible, options: NSStringCompareOptions)' to type 'UnicodeScalarLiteralConvertible'

Hoe kan ik de bestandsnaam van de extensie splitsen? Is er een elegante manier om dit te doen?

Ik was helemaal enthousiast over Swift omdat het een veel elegantere taal leek dan Objective C. Maar nu merk ik dat het zijn eigen omslachtigheid heeft.


Tweede poging: ik besloot mijn eigen string-zoekmethode te maken:

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
}

Maar nu krijg ik een foutmelding op de regel var rt: String.Index = rfind(fileName, needle: "."):

'Int' is not convertible to 'String.Index'

Zonder de cast krijg ik een foutmelding op de twee volgende regels.

Kan iemand me helpen deze bestandsnaam en extensie te splitsen?


Antwoord 1, autoriteit 100%

Swift 5.0-update:

Zoals aangegeven in de opmerking, kunt u dit gebruiken.

let filename: NSString = "bottom_bar.png"
let pathExtention = filename.pathExtension
let pathPrefix = filename.deletingPathExtension

Antwoord 2, autoriteit 75%

Dit is met Swift 2, Xcode 7: als je de bestandsnaam hebt met de extensie er al op, dan kun je de volledige bestandsnaam doorgeven als de eerste parameter en een lege string als de tweede parameter:

let soundURL = NSBundle.mainBundle()
    .URLForResource("soundfile.ext", withExtension: "")

Alternatief nul omdat de extensieparameter ook werkt.

Als je een URL hebt en je wilt om de een of andere reden de naam van het bestand zelf, dan kun je dit doen:

soundURL.URLByDeletingPathExtension?.lastPathComponent

Swift 4

let soundURL = NSBundle.mainBundle().URLForResource("soundfile.ext", withExtension: "")
soundURL.deletingPathExtension().lastPathComponent

Antwoord 3, autoriteit 53%

Werkt in Swift 5. Deze gedragingen toevoegen aan de klasse String:

extension String {
    func fileName() -> String {
        return URL(fileURLWithPath: self).deletingPathExtension().lastPathComponent 
    }
    func fileExtension() -> String {
        return URL(fileURLWithPath: self).pathExtension
    }
}

Voorbeeld:

let file = "image.png"
let fileNameWithoutExtension = file.fileName()
let fileExtension = file.fileExtension()

Antwoord 4, autoriteit 2%

Swift 5

URL(string: filePath)?.pathExtension

Antwoord 5, autoriteit 2%

Swift 5met code suiker

extension String {
    var fileName: String {
       URL(fileURLWithPath: self).deletingPathExtension().lastPathComponent
    }
    var fileExtension: String{
       URL(fileURLWithPath: self).pathExtension
    }
}

Antwoord 6, autoriteit 2%

Probeer dit voor een eenvoudige Swift 4-oplossing

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"

Antwoord 7, autoriteit 2%

Swift 5

URL.deletingPathExtension().lastPathComponent

Antwoord 8

Swift 3.0

let sourcePath = NSURL(string: fnName)?.pathExtension
 let pathPrefix = fnName.replacingOccurrences(of: "." + sourcePath!, with: "")

Antwoord 9

Swift 3.x uitgebreide oplossing:

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)

bestandsnaamconstante bevat nu “bestandsnaam_v123.456


Antwoord 10

Een betere manier (of op zijn minst een alternatief in Swift 2.0) is om de eigenschap String pathComponents te gebruiken. Dit splitst de padnaam in een reeks strings. bijv.

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!

Antwoord 11

Ze hebben pathExtension om wat voor reden dan ook verwijderd.

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]

Antwoord 12

Een opgeruimd antwoord voor Swift 4 met een extensie van 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
    }
}

Zoals opgemerkt in Xcode, is de oorspronkelijke FileName de naam van het activum op het moment dat het is gemaakt of geïmporteerd.

Other episodes