Fix: rewrite FileAndExt

FileAndExt has now be completely rewritten and now works as may
reasonably be expected. The test cases for:

ReplaceExtension
Filename
FileAndExt

now all pass.

The problem was the way path.Base was being used.
Firstly Base returns "." if the directory is empty, but it can also
return "." for the current directory, or ".." for the parent directory,
if these are the last elements in the path. Simply detecting the
presence of a "." in the returned string and truncating before the "."
does not therefore always result in a valid filename.
Secondly, Base strips any trailing slashes making is more difficult to
detect when the path does not end in a filename but in a directory name
i.e. a no filename case. Not detecting this incorrectly results in the
last directory name being returned as the filename.

The code has been updated to take account of of both situations so that:
1) An empty string for both the filename and extension is returned if the
path does not contain a filename (plus an optional extension). This
includes both the empty path case, and the ends in a directory case.
2) If the path represents a filename with an extension then both the
filename and the extension (minus any dots) are returned as non empty
strings.
3) If the path represents a filename without an extension then filename
will be returned as a non empty string (minus any dot) and the extension
will be returned as an empty string.
This commit is contained in:
Owen Waller 2014-09-22 18:40:09 +01:00 committed by spf13
parent 5906c8652d
commit f81f9ceb40

View file

@ -158,16 +158,38 @@ func Filename(in string) (name string) {
return return
} }
// FileAndExt returns the filename and any extension of a file path as
// two separate strings.
// If path, in, contains a directory name ending in a slash then
// both name and ext will be empty strings.
// If the path, in, is either the current directory, the parent
// directory or the root directory, or an empty string, then both
// name and ext will be empty strings.
// If the path, in, represents the path of a file without an extension
// then name will be the name of the file and ext will be an empty string.
// If the path, in, represents a filename with an extension then
// then name will be the filename minus any extension - including the dot
// and ext will contain the extension - minus the dot.
func FileAndExt(in string) (name string, ext string) { func FileAndExt(in string) (name string, ext string) {
ext = path.Ext(in) ext = path.Ext(in)
base := path.Base(in) base := path.Base(in) // path.Base strips any trailing slash!
if strings.Contains(base, ".") { // No file name cases. These are defined as:
// 1. any "in" path that ends in a os.PathSeparator i.e. "/" on linux
// 2. any "base" consisting of just an os.PathSeparator
// 3. any "base" consisting of just an empty string
// 4. any "base" consisting of just the current directory i.e. "."
// 5. any "base" consisting of just the parent directory i.e. ".."
if (strings.LastIndex(in, string(os.PathSeparator)) == len(in)-1) || base == "" || base == "." || base == ".." || base == string(os.PathListSeparator) {
name = "" // there is NO filename
} else if ext != "" { // there was an Extension
// return the filename minus the extension (and the ".")
name = base[:strings.LastIndex(base, ".")] name = base[:strings.LastIndex(base, ".")]
} else { } else {
name = in // no extension case so just return base, which willi
// be the filename
name = base
} }
return return
} }