16

When trying to remove the suffix from a filename, I'm only left with the suffix, which is exactly not what I want.

What (how many things) am I doing wrong here:

let myTextureAtlas = SKTextureAtlas(named: "demoArt")

let filename = (myTextureAtlas.textureNames.first?.characters.split{$0 == "."}.map(String.init)[1].replacingOccurrences(of: "\'", with: ""))! as String

print(filename)

This prints png which is the most dull part of the whole thing.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Confused
  • 6,048
  • 6
  • 34
  • 75

11 Answers11

38

If by suffix you mean path extension, there is a method for this:

let filename = "demoArt.png"
let name = (filename as NSString).deletingPathExtension
// name - "demoArt"
Jovan Stankovic
  • 4,661
  • 4
  • 27
  • 16
13

Some people here seem to overlook that a filename can have multiple periods in the name and in that case only the last period separates the file extension. So this.is.a.valid.image.filename.jpg and stripping the extension should return this.is.a.valid.image.filename and not this (as two answers here would produce) or anything else in between. The regex answer works correctly but using a regex for that is a bit overkill (probably 10 times slower than using simple string processing). Here's a generic function that works for everyone:

func stripFileExtension ( _ filename: String ) -> String {
    var components = filename.components(separatedBy: ".")
    guard components.count > 1 else { return filename }
    components.removeLast()
    return components.joined(separator: ".")
}

print("1: \(stripFileExtension("foo"))")
print("2: \(stripFileExtension("foo.bar"))")
print("3: \(stripFileExtension("foo.bar.foobar"))")

Output:

foo
foo
foo.bar
Mecki
  • 125,244
  • 33
  • 244
  • 253
11

You can also split the String using componentsSeparatedBy, like this:

let fileName = "demoArt.png"
var components = fileName.components(separatedBy: ".")
if components.count > 1 { // If there is a file extension
  components.removeLast()
  return components.joined(separator: ".")
} else {
  return fileName
}

To clarify:

fileName.components(separatedBy: ".")

will return an array made up of "demoArt" and "png".

WestCoastProjects
  • 58,982
  • 91
  • 316
  • 560
Wyetro
  • 8,439
  • 9
  • 46
  • 64
8

In iOS Array start with 0 and you want name of the file without extension, so you have split the string using ., now the name will store in first object and extension in the second one.

Simple Example

let fileName = "demoArt.png"
let name = fileName.characters.split(".").map(String.init).first
Nirav D
  • 71,513
  • 12
  • 161
  • 183
  • argh, so this is a very powerful little piece of code, splitting and storing the name, first part in position[0], second part in position [1]. What's the name of this array? map? – Confused Oct 06 '16 at 05:23
  • 1
    `split(".")` returns character View and using map function we have created String from it, if you don't use `.first` then name will be array with two objects. – Nirav D Oct 06 '16 at 05:25
  • ¿Why does your line not need the very confusing: $0== – Confused Oct 06 '16 at 06:07
  • @Confused `characters` will use to iterate through the all the characters of string one by one, if you write `.split { $0 == "." }`, here $0, iterate one by one characters of string and check for `.` but you can also directly use split function like `split(".")`. – Nirav D Oct 06 '16 at 06:15
  • @Confused Also the syntax you are using is used split with closure and i have used it `split()` function. – Nirav D Oct 06 '16 at 06:26
  • argh, got it. I'm going to try incorporate it in a loop to go through an array of textures as per what comes out of this question: http://stackoverflow.com/questions/39811334/folder-of-images-create-and-fill-skshapenodes-1-of-each and let you know my results... – Confused Oct 06 '16 at 20:24
  • GOT IT! Had to make a couple of little changes. Added a force unwrap at end and needed an argument label as per new Swift 3.0: for name in arrayOfFileNames { let fileNameWithoutSuffix = name.characters.split(separator: ".").map(String.init).first! print(fileNameWithoutSuffix) } – Confused Oct 06 '16 at 20:37
8

If you don't care what the extension is. This is a simple way.

let ss = filename.prefix(upTo: fileName.lastIndex { $0 == "." } ?? fileName.endIndex))

You may want to convert resulting substring to String after this. With String(ss)

possen
  • 8,596
  • 2
  • 39
  • 48
  • how does this work? Sorry. I'm a little dense, and need explanations. – Confused Apr 20 '18 at 12:23
  • 1
    Sorry there was a slight issue with my original code, hopefully the change I made will help understanding. To explain, the prefix function searches a collection, in this case a string, until it finds one matching the character, it returns a substring with all those characters prior to the matched character. The `String(` calls the constructor converting the substring to a regular string. – possen Apr 20 '18 at 19:05
  • If you have asd.asd/asd.es this is a bad answer. – Ariel Antonio Fundora Apr 11 '19 at 10:38
  • OK fixed it to handle the case presented by Ariel. – possen Apr 15 '19 at 20:12
6

@Confused with Swift 4 you can do this:

let fileName = "demoArt.png"
// or on your specific case:
// let fileName = myTextureAtlas.textureNames.first

let name = String(fileName.split(separator: ".").first!)
print(name)

Additionally you should also unwrapp first but I didn't want to complicate the sample code to solve your problem.

Btw, since I've also needed this recently, if you want to remove a specific suffix you know in advance, you can do something like this:

let fileName = "demoArt.png"
let fileNameExtension = ".png"

if fileName.hasSuffix(fileNameExtension) {
    let name = fileName.prefix(fileName.count - fileNameExtension.count)
    print(name)
}
Ricardo Barroso
  • 634
  • 9
  • 11
  • 1
    @Moritz, yeah. I did add it because I was getting a warning here, probably because I started with different code. It's fixed now, thanks. – Ricardo Barroso Dec 07 '17 at 19:31
5

How about using .dropLast(k) where k is the number of characters you drop from the suffix ?

Otherwise for removing extensions from path properly from filename, I insist you to use URL and .deletingPathExtension().lastPathComponent.

Maybe a bit overhead but at least it's a rock solid Apple API.

Laszlo
  • 2,803
  • 2
  • 28
  • 33
2

You can also use a Regexp to extract all the part before the last dot like that :

let fileName = "test.png"
let pattern  = "^(.*)(\\.[a-zA-Z]+)$"
let regexp = try! NSRegularExpression(pattern: pattern, options: [])
let extractedName = regexp.stringByReplacingMatches(in: fileName, options: [], range: NSMakeRange(0, fileName.characters.count), withTemplate: "$1")
print(extractedName) //test
CZ54
  • 5,488
  • 1
  • 24
  • 39
  • Strewth. Way beyond my stringFu, but very cool to know. I'm sure I'll need it quite soon... THANK YOU! – Confused Oct 06 '16 at 21:03
2
let mp3Files = ["alarm.mp3", "bubbles.mp3", "fanfare.mp3"]
let ringtonsArray = mp3Files.flatMap { $0.components(separatedBy: ".").first }
pacification
  • 5,838
  • 4
  • 29
  • 51
Melany
  • 466
  • 7
  • 20
2

You can return a new string removing a definite number of characters from the end.

   let fileName = "demoArt.png"
   fileName.dropLast(4)

This code returns "demoArt"

1

One liner:

let stringWithSuffixDropped = fileName.split(separator: ".").dropLast().joined(separator: ".")
ATV
  • 4,116
  • 3
  • 23
  • 42