Files icon indicating copy to clipboard operation
Files copied to clipboard

nameExcludingExtension removes all "."

Open jpmhouston opened this issue 4 years ago • 2 comments

For file named "Dots.in.place.of.spaces.txt", nameExcludingExtension should return "Dots.in.place.of.spaces" but instead returns "Dotsinplaceofspaces".

jpmhouston avatar Mar 15 '20 19:03 jpmhouston

This could prove problematic to solve because names that have dots in them, but don't have an extension (Some.Image.Without.An.Extension, or worse Some.File_With_Mixed_Delimeters), can't easily be recognized.

My initial solution would be this:

    /// The name of the location, excluding its `extension`.
    var nameExcludingExtension: String {
        let components = name.split(separator: ".")
        guard components.count > 1 else { return name }
        return components.dropLast().joined(separator: ".") // Re-join the name with dots
    }

But it fails on this test:

    func testNameExcludingExtensionWithFileNameIncludingDots() {
        performTest {
            let file = try folder.createFile(named: "File.Name.With.Dots.txt")
            let subfolder = try folder.createSubfolder(named: "Subfolder.With.Dots")

            XCTAssertEqual(file.nameExcludingExtension, "File.Name.With.Dots")
            XCTAssertEqual(subfolder.nameExcludingExtension, "Subfolder.With.Dots") // XCTAssertEqual failed: ("Subfolder.With") is not equal to ("Subfolder.With.Dots")
        }
    }

clayellis avatar Mar 16 '20 15:03 clayellis

@clayellis Thanks for your code examples and test cases which I appreciate, since I ran into this issue as well.

I guess the problem is two folded:

  1. What is a correct file extension?
  2. When provided a filename with a correct extension, does the code return the correct name excluding the extension?

For my use case I solved 1) by validating macOS Uniform Type Identifiers and 2) by the following code:

extension Location {
    var nameWithoutExtension: String {
        return self.name
    }
}

extension File {
    var nameWithoutExtension: String {
        guard let ext = self.extension else { return self.name }
        return String(self.name.replacingOccurrences(of: ext, with: "", options: .backwards).dropLast())
    }
}

Happy to submit a PR based on the above snippets, if people feel this is an improvement over the current version?

marwey avatar May 03 '20 21:05 marwey