web-dev-qa-db-ja.com

Swiftでファイル拡張子からファイル名を分割する方法は?

バンドル内のファイルの名前を指定して、ファイルをSwiftアプリにロードします。だから私はこのメソッドを使用する必要があります:

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

何らかの理由で、メソッドはファイル拡張子から分離されたファイル名を必要とします。たいていの場合、ほとんどの言語で2つを簡単に分離できます。しかし、これまでのところ、私はそれがスウィフトでそうであることがわかりません。

だからここに私が持っているものがあります:

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

最初の行に入力を含めないと、後続の2行にエラーが表示されます。それにより、最初の行にエラーが表示されます:

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

拡張子からファイル名を分割するにはどうすればよいですか?これを行うエレガントな方法はありますか?

Swiftにはとても興奮していました。ObjectiveCよりもはるかにエレガントな言語のように思えたからです。


2回目の試み:私は独自の文字列検索方法を作成することにしました:

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'

キャストを行わないと、後続の2行でエラーが発生します。

誰でもこのファイル名と拡張子を分割するのを手伝ってくれますか?

57
JohnK

これはSwift 2、Xcode 7を使用する場合:拡張子が既に付いているファイル名がある場合、最初のパラメーターとして完全なファイル名を、2番目のパラメーターとして空の文字列を渡すことができます。

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

または、拡張パラメータとしてnilも機能します。

URLがあり、何らかの理由でファイル自体の名前を取得したい場合、これを行うことができます。

soundURL.URLByDeletingPathExtension?.lastPathComponent

Swift 4

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

コメントで指摘したように、これを使用できます。

let filename: NSString = "bottom_bar.png"
let pathExtention = filename.pathExtension
let pathPrefix = filename.stringByDeletingPathExtension
86
gabbler

Swift 3/Swiftで動作します4.これらの動作をStringクラスに追加します。

extension String {

    func fileName() -> String {
        return NSURL(fileURLWithPath: self).deletingPathExtension?.lastPathComponent ?? ""
    }

    func fileExtension() -> String {
        return NSURL(fileURLWithPath: self).pathExtension ?? ""
    }
}

例:

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

Swift 2.1では、String.pathExtensionは使用できなくなりました。代わりに、NSURL変換によって決定する必要があります。

NSURL(fileURLWithPath: filePath).pathExtension
28
Santanu Karar

ソリューション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
27
Lore

SwiftでNSStringに変更すると、拡張機能をより速く取得できます。

extension String {
    func getPathExtension() -> String {
        return (self as NSString).pathExtension
    }
}
13

Swift 2.1では、これを行う現在の方法は次のように思われます:

let filename = fileURL.URLByDeletingPathExtension?.lastPathComponent
let extension = fileURL.pathExtension
5
Aneel

Swift 3.x Shortest Native Solution

let fileName:NSString = "the_file_name.mp3"
let onlyName = fileName.deletingPathExtension
let onlyExt = fileName.pathExtension

拡張子や余分なものはありません(私はテストしました。Swift 2の@gabblerソリューションに基づいています)

3
Trevor

最新のSwift 4.2は次のように機能します。

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

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

Swiftの文字列は間違いなくトリッキーです。純粋なSwiftメソッドが必要な場合は、次のようにします。

  1. find を使用して、文字列の reverse"."の最後の出現を検索します。
  2. advance を使用して、元の文字列の"."の正しいインデックスを取得します
  3. Stringを使用して文字列を取得するsubscriptIntervalType関数を使用します
  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

または、単に 既に利用可能なNSStringメソッド を使用してください pathExtension および stringByDeletingPathExtension .

2
Mike S

シンプルな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"
2
Eng Yew

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」が含まれるようになりました

スイフト5

 URL(string: filePath)?.pathExtension
1
Den

Swift 3.0

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

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は、作成またはインポートされた時点のアセットの名前です。

0
CodeBender

以前の2つのフォルダーを含む一意の「ファイル名」フォーム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
}
0
Pvlub

より良い方法(または少なくとも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!
0
Derek Knight

たぶんこれには手遅れになっているかもしれませんが、私にとってはうまくいき、非常に簡単だと考える解決策は、#fileコンパイラ指令を使用することです。/Tests/MyProjectTests/FixturesFixtureManager.SwiftSwiftテスト内のdirectory. This works both in Xcode and withで定義されているクラスFixtureManagerがある例です

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)
    }

}
0
GuidoMB

なんらかの理由で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]
0
Pescolly