【问题标题】:How to split filename from file extension in Swift?如何在 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 看看它会很好。

标签: ios string swift


【解决方案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.pathExtensionlet 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

【讨论】:

【解决方案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 方法,我会这样做:

          1. 使用find 在字符串的reverse 中查找"." 的最后一次出现
          2. 使用advance获取"."在原字符串中的正确索引
          3. 使用Stringsubscript 函数,该函数采用IntervalType 来获取字符串
          4. 将这一切打包在一个函数中,该函数返回名称和扩展名的可选元组

          类似这样的:

          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,例如pathExtensionstringByDeletingPathExtension

          【讨论】:

            【解决方案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 withswift 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
                              }
                              

                              【讨论】:

                                猜你喜欢
                                • 2011-05-17
                                • 2012-12-19
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2011-05-31
                                • 1970-01-01
                                • 2012-06-29
                                • 1970-01-01
                                相关资源
                                最近更新 更多