如何在 Swift 中从文件扩展名中拆分文件名?
Posted
技术标签:
【中文标题】如何在 Swift 中从文件扩展名中拆分文件名?【英文标题】:How to split filename from file extension in Swift? 【发布时间】:2014-11-03 03:29:30 【问题描述】:给定包中文件的名称,我想将文件加载到我的 Swift 应用程序中。所以我需要使用这个方法:
let soundURL = NSBundle.mainBundle().URLForResource(fname, withExtension: ext)
无论出于何种原因,该方法都需要将文件名与文件扩展名分开。好吧,在大多数语言中将两者分开很容易。但到目前为止,我发现它在 Swift 中并非如此。
这就是我所拥有的:
var rt: String.Index = fileName.rangeOfString(".", options:NSStringCompareOptions.BackwardsSearch)
var fname: String = fileName .substringToIndex(rt)
var ext = fileName.substringFromIndex(rt)
如果我不包括第一行的输入,我会在随后的两行中得到错误。有了它,我在第一行得到一个错误:
Cannot convert the expression's type '(UnicodeScalarLiteralConvertible, options: NSStringCompareOptions)' to type 'UnicodeScalarLiteralConvertible'
如何从扩展名中拆分文件名?有什么优雅的方法可以做到这一点吗?
我对 Swift 感到非常兴奋,因为它似乎是一种比 Objective C 更优雅的语言。但现在我发现它也有它自己的麻烦。
第二次尝试:我决定制作自己的字符串搜索方法:
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
但是现在我在var rt: String.Index = rfind(fileName, needle: ".")
这一行收到错误:
'Int' is not convertible to 'String.Index'
如果没有演员表,我会在随后的两行中收到错误。
谁能帮我拆分这个文件名和扩展名?
【问题讨论】:
您是否查看过专门用于处理路径的 NSString 方法(如 lastPathComponent 和 stringByDeletingPathExtension)? 你知道,如果我们 Objective-C 用户不得不忍受为了合并 Swift 而对文档所做的破坏行为,如果你 Swifties 看看它会很好。 【参考方案1】:Swift 5.0 更新:
正如评论中指出的,你可以使用这个。
let filename: NSString = "bottom_bar.png"
let pathExtention = filename.pathExtension
let pathPrefix = filename.deletingPathExtension
【讨论】:
由于 Swift 的 String 类型与 Foundation 的 NSString 类无缝桥接,因此无需创建新的 NSString。只需使用let pathExtension = filename.pathExtension
和let pathPrefix = filename.stringByDeletingPathExtension
。
为了访问 stringByDeletingPathExtension,您必须将文件名转换为 NSString - 让 pathPrefix = (filename as NSString).stringByDeletingPathExtension。 pathExtension 也一样。
更新名称已更改:stringByDeletingPathExtension 现在正在删除PathExtension
看来你现在必须let filename: NSString = "bottom_bar.png" as NSString
。
应该是let pathPrefix = filename.deletingPathExtension
【参考方案2】:
这适用于 Swift 2、Xcode 7:如果您的文件名已经带有扩展名,那么您可以将完整的文件名作为第一个参数传入,并将空白字符串作为第二个参数传入:
let soundURL = NSBundle.mainBundle()
.URLForResource("soundfile.ext", withExtension: "")
nil 作为扩展参数也可以使用。
如果您有一个 URL,并且出于某种原因想要获取文件本身的名称,那么您可以这样做:
soundURL.URLByDeletingPathExtension?.lastPathComponent
斯威夫特 4
let soundURL = NSBundle.mainBundle().URLForResource("soundfile.ext", withExtension: "")
soundURL.deletingPathExtension().lastPathComponent
【讨论】:
这应该是推荐的答案!完美运行 确实如此,据记载,您可以传递整个文件名并将扩展名保留为 nil 或为空:developer.apple.com/library/mac/documentation/Cocoa/Reference/…:【参考方案3】:适用于 Swift 5。将这些行为添加到 String
类:
extension String
func fileName() -> String
return URL(fileURLWithPath: self).deletingPathExtension().lastPathComponent
func fileExtension() -> String
return URL(fileURLWithPath: self).pathExtension
示例:
let file = "image.png"
let fileNameWithoutExtension = file.fileName()
let fileExtension = file.fileExtension()
【讨论】:
只是样式,但我更喜欢变体:public var fileExtension: String return NSURL(fileURLWithPath: self).pathExtension.lowercaseString ?? ""
// 假设我们希望 .JPG 雅虎不区分大小写
在 Swift 3 中你应该使用 URL
而不是 NSURL
。【参考方案4】:
解决方案 Swift 4
此解决方案适用于所有实例,不依赖于手动解析字符串。
let path = "/Some/Random/Path/To/This.Strange.File.txt"
let fileName = URL(fileURLWithPath: path).deletingPathExtension().lastPathComponent
Swift.print(fileName)
结果输出将是
This.Strange.File
【讨论】:
这为我节省了很多自定义格式化时间,谢谢!【参考方案5】:在 Swift 2.1 中,String.pathExtension 不再可用。而是需要通过 NSURL 转换来确定:
NSURL(fileURLWithPath: filePath).pathExtension
【讨论】:
但是,NSString.pathExtension
仍然可用,因此您可以简单地将其转换为 NSString:(pathString as NSString).pathExtension
。
这很好用,但是最好使用URL
类而不是NSURL
【参考方案6】:
在 Swift 中,您可以更改为 NSString
以更快地获得扩展:
extension String
func getPathExtension() -> String
return (self as NSString).pathExtension
【讨论】:
【参考方案7】:最新的 Swift 4.2 是这样工作的:
extension String
func fileName() -> String
return URL(fileURLWithPath: self).deletingPathExtension().lastPathComponent
func fileExtension() -> String
return URL(fileURLWithPath: self).pathExtension
【讨论】:
【参考方案8】:在 Swift 2.1 中,目前的做法似乎是:
let filename = fileURL.URLByDeletingPathExtension?.lastPathComponent
let extension = fileURL.pathExtension
【讨论】:
【参考方案9】:SWIFT 3.x 最短原生解决方案
let fileName:NSString = "the_file_name.mp3"
let onlyName = fileName.deletingPathExtension
let onlyExt = fileName.pathExtension
没有扩展或任何额外的东西 (我已经测试过了。基于 Swift 2 的 @gabbler 解决方案)
【讨论】:
【参考方案10】:Swift 中的字符串肯定会很棘手。如果你想要一个纯 Swift 方法,我会这样做:
-
使用
find
在字符串的reverse
中查找"."
的最后一次出现
使用advance
获取"."
在原字符串中的正确索引
使用String
的subscript
函数,该函数采用IntervalType
来获取字符串
将这一切打包在一个函数中,该函数返回名称和扩展名的可选元组
类似这样的:
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
会这样使用:
let str = "/Users/me/Documents/Something.something/text.txt"
if let split = splitFilename(str)
println(split.name)
println(split.ext)
哪些输出:
/Users/me/Documents/Something.something/text
txt
或者,只需使用already available NSString
methods,例如pathExtension
和stringByDeletingPathExtension
。
【讨论】:
【参考方案11】:斯威夫特 5
URL(string: filePath)?.pathExtension
【讨论】:
【参考方案12】:Swift 5 带代码糖
extension String
var fileName: String
URL(fileURLWithPath: self).deletingPathExtension().lastPathComponent
var fileExtension: String
URL(fileURLWithPath: self).pathExtension
【讨论】:
【参考方案13】:试试这个简单的 Swift 4 解决方案
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"
【讨论】:
【参考方案14】:斯威夫特 5
URL.deletingPathExtension().lastPathComponent
【讨论】:
【参考方案15】:斯威夫特 3.0
let sourcePath = NSURL(string: fnName)?.pathExtension
let pathPrefix = fnName.replacingOccurrences(of: "." + sourcePath!, with: "")
【讨论】:
【参考方案16】:Swift 3.x 扩展解决方案:
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)
文件名常量现在包含“filename_v123.456”
【讨论】:
【参考方案17】:更好的方法(或者至少是 Swift 2.0 中的替代方法)是使用 String pathComponents 属性。这会将路径名拆分为字符串数组。例如
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!
【讨论】:
【参考方案18】:无论出于何种原因,他们都摆脱了 pathExtension。
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]
【讨论】:
这仅在文件名包含一个点时才有效。不能使用更多的点,没有它们就会崩溃.. 如果没有任何句点,则该文件没有正确的扩展名。如果有多个句点,那么您可以使用 let ext = l.last?.componentsSeparatedByString(".").last. 获取扩展名【参考方案19】: Swift 4 的干净答案,扩展名为 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
如 XCode 中所述,originalFilename 是资产在创建或导入时的名称。
【讨论】:
【参考方案20】:也许我为时已晚,但一个对我有用且认为非常简单的解决方案是使用#file
编译器指令。这是一个示例,其中我有一个类FixtureManager
,在/Tests/MyProjectTests/Fixturesdirectory. This works both in Xcode and with
swift test 内的FixtureManager.swift
中定义`
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)
【讨论】:
【参考方案21】:创建唯一的“文件名”表单 url,包括两个先前的文件夹
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
【讨论】:
以上是关于如何在 Swift 中从文件扩展名中拆分文件名?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 中从文件夹中获取 UIImage 数组?