Swift URL values can separate a file name from its extension.

Split a file name

fileName
file_extensions.swift
Replay: real traced execution (multi-file project)
import Foundation

let fileName = "lesson.swift"
let url = URL(fileURLWithPath: fileName)
let base = url.deletingPathExtension().lastPathComponent
let ext = url.pathExtension
let message = "base=\(base) ext=\(ext)"

print(message)
import Foundation

let fileName = "notes.md"
let url = URL(fileURLWithPath: fileName)
let base = url.deletingPathExtension().lastPathComponent
let ext = url.pathExtension
let message = "base=\(base) ext=\(ext)"

print(message)
import Foundation

let fileName = "archive.tar"
let url = URL(fileURLWithPath: fileName)
let base = url.deletingPathExtension().lastPathComponent
let ext = url.pathExtension
let message = "base=\(base) ext=\(ext)"

print(message)
  1. fileName ← lesson.swift, url ← lesson.swift -- file:///app/, base ← lesson

    3let fileName→ lesson.swift = "lesson.swift"  //@fileName="notes.md", "archive.tar"4let url→ lesson.swift -- file:///app/ = URL(fileURLWithPath: fileNamelesson.swift)5let base→ lesson = url.deletingPathExtension().lastPathComponentlesson6let ext→ swift = url.pathExtensionswift7let message→ base=lesson ext=swift = "base=\(baselesson) ext=\(extswift)"89print(messagebase=lesson ext=swift)
    outputbase=lesson ext=swift
  1. fileName ← notes.md, url ← notes.md -- file:///app/, base ← notes

    3let fileName→ notes.md = "notes.md"4let url→ notes.md -- file:///app/ = URL(fileURLWithPath: fileNamenotes.md)5let base→ notes = url.deletingPathExtension().lastPathComponentnotes6let ext→ md = url.pathExtensionmd7let message→ base=notes ext=md = "base=\(basenotes) ext=\(extmd)"89print(messagebase=notes ext=md)
    outputbase=notes ext=md
  1. fileName ← archive.tar, url ← archive.tar -- file:///app/, base ← archive

    3let fileName→ archive.tar = "archive.tar"4let url→ archive.tar -- file:///app/ = URL(fileURLWithPath: fileNamearchive.tar)5let base→ archive = url.deletingPathExtension().lastPathComponentarchive6let ext→ tar = url.pathExtensiontar7let message→ base=archive ext=tar = "base=\(basearchive) ext=\(exttar)"89print(messagebase=archive ext=tar)
    outputbase=archive ext=tar
file extension `pathExtension` reads the extension, and `deletingPathExtension` keeps the base name.