+ Reply to Thread
Results 1 to 13 of 13

File & Folder Names Functions - Back to Basics

Hybrid View

  1. #1
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    File & Folder Names Functions - Back to Basics

    Some clarification as to descriptions I use:
    • FullName = Path + FileName (Includes Drive + FileExt if present) (e.g. C:\path\filename.ext)
    • Path = Folder path only (Including Drive). Should not include FileName. May or may not end with a PathSeparator (e.g. C:\path\ or C:\path )
    • FileName = Name of file (Includes FileExt if present). Should not include Path (e.g. filename.ext)


    Lately I've been pondering extracting information from file & folder names.

    We already know how to do this!

    Are you certain about that?


    Here's a test - how do you write a function to return the file path from a FullName string?



    I am guessing that most would answer something like this:
    Function sGetPath(sFullName as String) as String
    sGetPath= Left(sFullName , InStrRev(sFullName , Application.PathSeparator))
    End Function

    But what if someone passes a Path instead of a FullName argument?

    Our function could fail. (e.g. "C:\path1\path2" would return as "C:\path1\" - we would lose part of the folder path without realising)


    So I've felt the need to rethink the basics of any procedures that deal with file/folder names.

    I want the functions to avoid returning incorrect results - as far as possible - regardless of whether the input is a fullname / filepath / filename

    (e.g. a function for returning folder path should return an empty string where the input was a filename)


    At this point, someone will say "why don't you validate the file/folder existence with Dir or FSO"?

    But that won't work if you are dealing with a worksheet range listing files and/or folders from another PC.


    So after some tinkering, below is as far as I can reach. If anyone can think of a way to tighten these functions, I'd be interested!

    Option Explicit
    
    Public Sub DevTestFileNameFunctions()
    '/ this procedure for testing the file/folder name functions
        Const strcDRIVE As String = "C:"
        Const strcPATH1 As String = "path1"
        Const strcPATH2 As String = "path2"
        Const strcFNAME As String = "filename"
        Const strcEXT1 As String = "ext1"
        Const strcEXT2 As String = "ext2"
        Const strcSEP_PATH As String = "\"
        Const strcSEP_EXT As String = "."
    
        Dim avarTestFileFolders() As Variant
        Dim abytLoop As Byte
        Dim strOutput As String
        Dim strInput As String
    
        ReDim avarTestFileFolders(1 To 15)
        avarTestFileFolders(1) = strcDRIVE
        avarTestFileFolders(2) = strcDRIVE & strcSEP_PATH
        avarTestFileFolders(3) = strcDRIVE & strcSEP_PATH & strcPATH1
        avarTestFileFolders(4) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH
        avarTestFileFolders(5) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2
        avarTestFileFolders(6) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH
        avarTestFileFolders(7) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & strcFNAME
        avarTestFileFolders(8) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & strcFNAME & strcSEP_EXT & strcEXT1
        avarTestFileFolders(9) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
        avarTestFileFolders(10) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_EXT & strcPATH2 & strcSEP_PATH & strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
        avarTestFileFolders(11) = ""
        avarTestFileFolders(12) = Empty
        avarTestFileFolders(13) = strcFNAME
        avarTestFileFolders(14) = strcFNAME & strcSEP_EXT & strcEXT1
        avarTestFileFolders(15) = strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
    
        Debug.Print Now() & vbTab & "test started"
    
        For abytLoop = LBound(avarTestFileFolders) To UBound(avarTestFileFolders)
    
            strOutput = vbNullString
            strInput = vbNullString
            strInput = (avarTestFileFolders(abytLoop))
    
    'change the procedure name here to the one you want to test
            strOutput = fnstrGetPathFromFullName(strInput)
    
    'RESULTS:
    
    ' fnstrGetPathFromFullName
    '   FAILED = 1,3,5
    
    ' fnstrGetFileNameFromFullName(False)
    '   FAILED = 1,3,5
    
    ' fnstrGetFileNameFromFullName(True)
    '   FAILED = 7,13
    
    ' fnstrGetFileExtFromFileName(True or False)
    '   ALL PASSED
    
    
            Debug.Print Format(abytLoop, "00") _
                & Space(2) & "READ: " & strOutput _
                & Space(35 - Len(strOutput)) & vbTab & "FROM: " & avarTestFileFolders(abytLoop)
        Next abytLoop
    
        Debug.Print Now() & vbTab & "test completed"
    End Sub
    
    Public Function fnstrGetPathFromFullName(ByRef strFullName As String) As String
        fnstrGetPathFromFullName = Left(strFullName, InStrRev(strFullName, Application.PathSeparator))
    End Function
    
    Public Function fnstrGetFileNameFromFullName(ByRef strFullName As String, Optional ByVal blnCheckHasExt As Boolean) As String
    '/ some poor inputs can return incorrect results (e.g. "C:", "C:\path1")
    '/ partially fixed this by adding optional Arg to check for extension separator (which in turn fails on files missing extensions)
    
        Dim bytPosPathSep As Byte
    
        If Not Len(strFullName) > 0 Then
            Exit Function
        End If
    
        If blnCheckHasExt Then
            'this optional arg has good & bad points
            'good = ignores garbage input
            'bad = overlooks any file missing ext
            If Not InStr(strFullName, ".") > 0 Then
                Exit Function
            End If
        End If
    
        bytPosPathSep = InStrRev(strFullName, Application.PathSeparator)
    
        fnstrGetFileNameFromFullName = Mid(strFullName, bytPosPathSep + 1)
    End Function
    
    Public Function fnstrGetFileExtFromFileName(ByRef strFileName As String, Optional ByVal blnRemoveMultiExt As Boolean) As String
        Dim bytPosExtSep As Byte
        Dim bytPosPathSep As Byte
    
        If blnRemoveMultiExt Then
            bytPosPathSep = InStrRev(strFileName, Application.PathSeparator)
            bytPosExtSep = InStr(bytPosPathSep + 1, strFileName, ".")
        Else
            bytPosExtSep = InStrRev(strFileName, ".", -1)
        End If
    
        If bytPosExtSep > 0 Then
            fnstrGetFileExtFromFileName = Right(strFileName, Len(strFileName) - bytPosExtSep)
        End If
    End Function
    
    Public Function fnstrRemoveFileExtFromFileName(ByVal strFileName As String, Optional ByVal blnRemoveMultiExt As Boolean) As String
        Dim strExt As String
        Dim bytPos As Byte
    
        strExt = "." & fnstrGetFileExtFromFileName(strFileName, blnRemoveMultiExt)
    
        bytPos = InStrRev(strFileName, strExt)
        If bytPos > 0 Then
            fnstrRemoveFileExtFromFileName = Left(strFileName, bytPos - 1)
        Else
            fnstrRemoveFileExtFromFileName = strFileName
        End If
    End Function

    UPDATE:
    I could alter the fnstrGetPathFromFullName procedure so that it checks for a file extension seperator - similar to what I did in fnstrGetFileNameFromFullName
    But it would still fail on filenames that lack extensions
    Last edited by mc84excel; 11-16-2014 at 07:15 PM. Reason: removed unimportant (post 2&3), clarify function failure
    *******************************************************

    HELP WANTED! (Links to Forum threads)
    Trying to create reusable code for Custom Events at Workbook (not Application) level

    *******************************************************

  2. #2
    Forum Expert shg's Avatar
    Join Date
    06-20-2007
    Location
    The Great State of Texas
    MS-Off Ver
    2010, 2019
    Posts
    40,689

    Re: File & Folder Names Functions - Back to Basics

    FAIL to any who used anything relying on InStr!
    Aside from that it's InStrRev, not InStr, fail because ...?
    Entia non sunt multiplicanda sine necessitate

  3. #3
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    Re: File & Folder Names Functions - Back to Basics

    Quote Originally Posted by shg View Post
    Aside from that it's InStrRev, not InStr, fail because ...?
    Well I wanted to pick a beginner mistake to lighten the mood before getting down to the heart of the matter. I agree that I should have picked a better example. It could slightly derail the thread so I have removed this from the OP.

  4. #4
    Forum Expert romperstomper's Avatar
    Join Date
    08-13-2008
    Location
    England
    MS-Off Ver
    365, varying versions/builds
    Posts
    22,015

    Re: File & Folder Names Functions - Back to Basics

    Given that you can't tell the difference between a path and a filename without extension, what's the point? Also, you can use '.' in a folder name. In short, your goal is not achievable, but don't let that stop you.
    Last edited by romperstomper; 11-14-2014 at 04:24 AM.
    Everyone who confuses correlation and causation ends up dead.

  5. #5
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    Re: File & Folder Names Functions - Back to Basics

    Quote Originally Posted by romperstomper View Post
    Given that you can't tell the difference between a path and a filename without extension, what's the point?
    I'm not THAT crazy! I had already thought of that.

    And I agree. It would be impossible to get these functions 100% accurate from the file/folder name string alone. I realise and accept that.

    Instead I'm striving for as close as I can get to 100% accurate

    Quote Originally Posted by romperstomper View Post
    Also, you can use '.' in a folder name.
    True. But I rarely ever see this occur on the systems I use.

    (I could slightly reduce this risk by only checking for the '.' after the last '\' in the string. The problem with that is that I am then assuming the input argument is a FullName. It wouldn't work too well if the input was a FileName!)

    Quote Originally Posted by romperstomper View Post
    In short, your goal is not achievable, but don't let that stop you.
    Thanks Rory, but I'm thinking I didn't make my goal clear enough. I know it would be impossible to achieve 100% accuracy. And that's not what I was asking for in the OP. I asked if anyone could tighten the functions any further. (If you like - think of it as a theoretical challenge! )
    Last edited by mc84excel; 11-17-2014 at 12:11 AM.

  6. #6
    Forum Guru Kyle123's Avatar
    Join Date
    03-10-2010
    Location
    Leeds
    MS-Off Ver
    365 Win 11
    Posts
    7,239

    Re: File & Folder Names Functions - Back to Basics

    Pretty sure Dir() does this pretty well - in response to:
    But that won't work if you are dealing with a range listing files and/or folders from another PC.
    Code should check at runtime for the existence of a resource before trying to consume it, so this point is irrelevant.

  7. #7
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    Re: File & Folder Names Functions - Back to Basics

    Quote Originally Posted by Kyle123 View Post
    Pretty sure Dir() does this pretty well
    It does?

    I've found that Dir only works where the file or folder exists on the computer you are working on.

    i.e. If you Dir a string where the file or folder doesn't exist, it will return an error. This error forms the basis of the ExistsFileFolder function written by Ken Puls (see my badly rehashed copy below)

    Public Function fnblnExistsFileFolder(ByVal strFullName As String) As Boolean
    'adapted from function written by Ken Puls (www.excelguru.ca)
        If Len(strFullName) = 0 Then
            Exit Function
        End If
    
        On Error Resume Next
        fnblnExistsFileFolder = (Dir(strFullName, 31) <> vbNullString)
        On Error GoTo 0
    End Function

    Quote Originally Posted by Kyle123 View Post
    Code should check at runtime for the existence of a resource before trying to consume it, so this point is irrelevant.
    You are right. It should.

    But I still want to see how far I can take these functions anyway

  8. #8
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    Re: File & Folder Names Functions - Back to Basics

    A FileName does not, can not, have a Drive prefix - unlike a FullName or Path. (Note: can not = if it did then the string is not a FileName, it would be a FullName)

    So IF the input strings 2nd & 3rd characters are ":\" OR the first two characters are "\\" THEN ... (Note: "\\" for those pesky UNCs)

    hmmm I think I might be onto something here

  9. #9
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    Re: File & Folder Names Functions - Back to Basics

    Latest version. I've now eliminated 1 bad result from 2 of the functions (by using a reasonable assumption)

    Private Sub DevTestFileNameFunctions()
    '/ this procedure for testing the file/folder name functions
        Const strcDRIVE As String = "C:"
        Const strcPATH1 As String = "path1"
        Const strcPATH2 As String = "path2"
        Const strcFNAME As String = "filename"
        Const strcEXT1 As String = "ext1"
        Const strcEXT2 As String = "ext2"
        Const strcSEP_PATH As String = "\"
        Const strcSEP_EXT As String = "."
    
        Dim avarTestFileFolders() As Variant
        Dim abytLoop As Byte
        Dim strOutput As String
        Dim strInput As String
    
        ReDim avarTestFileFolders(1 To 15)
        avarTestFileFolders(1) = strcDRIVE
        avarTestFileFolders(2) = strcDRIVE & strcSEP_PATH
        avarTestFileFolders(3) = strcDRIVE & strcSEP_PATH & strcPATH1
        avarTestFileFolders(4) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH
        avarTestFileFolders(5) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2
        avarTestFileFolders(6) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH
        avarTestFileFolders(7) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & _
            strcFNAME
        avarTestFileFolders(8) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & _
            strcFNAME & strcSEP_EXT & strcEXT1
        avarTestFileFolders(9) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & _
            strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
        avarTestFileFolders(10) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_EXT & strcPATH2 & strcSEP_PATH & _
            strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
        avarTestFileFolders(11) = ""
        avarTestFileFolders(12) = Empty
        avarTestFileFolders(13) = strcFNAME
        avarTestFileFolders(14) = strcFNAME & strcSEP_EXT & strcEXT1
        avarTestFileFolders(15) = strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
    
        Debug.Print Now() & vbTab & "test started"
    
        For abytLoop = LBound(avarTestFileFolders) To UBound(avarTestFileFolders)
    
            strOutput = vbNullString
            strInput = vbNullString
            strInput = (avarTestFileFolders(abytLoop))
    
            strOutput = fnstrGetFileNameFromFullName(strInput)
    
    'RESULTS:
    '
    ' fnstrGetPathFromFullName
    '   FAILED = 3,5
    '
    ' fnstrGetFileNameFromFullName(False)
    '   FAILED = 3,5
    '
    ' fnstrGetFileNameFromFullName(True)
    '   FAILED = 7,13
    '
    ' fnstrGetFileExtFromFileName(True or False)
    '   ALL PASSED
    '
    
            Debug.Print Format(abytLoop, "00") & Space(2) & "READ: " & strOutput & Space(35 - Len(strOutput)) & _
                vbTab & "FROM: " & avarTestFileFolders(abytLoop)
        Next abytLoop
    
        Debug.Print Now() & vbTab & "test completed"
    End Sub
    
    Public Function fnstrGetSeparatoredPath(ByRef strPath As String) As String
    '/ ensure folder path ends in path separator
        If Not Len(strPath) > 0 Then
            Exit Function
        End If
    
        With Application
            If Right$(strPath, 1) = .PathSeparator Then
                fnstrGetSeparatoredPath = strPath
            Else
                fnstrGetSeparatoredPath = strPath & .PathSeparator
            End If
        End With
    End Function
    
    Public Function fnstrGetPathFromFullName(ByRef strFullName As String) As String
        Select Case Len(strFullName)
        Case Is > 3
            If (Mid$(strFullName, 2, 2) = ":\") Or (Left$(strFullName, 2) = "\\") Then
                'drive found - this cant be a FileName
                fnstrGetPathFromFullName = Left$(strFullName, InStrRev(strFullName, Application.PathSeparator))
            Else
                'assume is filename only
            End If
        Case 1 To 3
            'the likelihood of a filename len being less than 4 is *extremely unlikely* to occur in the real world
            'this is almost certainly a drive
            If Mid$(strFullName, 2, 1) = ":" Then
                fnstrGetPathFromFullName = strFullName
            End If
        Case Else
            'probably Null or vbnullstring
        End Select
    End Function
    
    Public Function fnstrGetFileNameFromFullName(ByRef strFullName As String, _
                                                Optional ByVal blnCheckHasExt As Boolean) As String
    '/ some poor inputs can return incorrect results (e.g. "C:", "C:\path1")
    '/ partially fixed this by adding optional Arg to check for extension separator (which in turn fails on files missing extensions)
    
        Dim bytPosPathSep As Byte
    
        Select Case Len(strFullName)
        Case Is > 3
            If blnCheckHasExt Then
                'this optional arg has good & bad points
                'good = ignores garbage input
                'bad = overlooks any file missing ext
                If Not InStr(strFullName, ".") > 0 Then
                    Exit Function
                End If
            End If
    
            bytPosPathSep = InStrRev(strFullName, Application.PathSeparator)
    
            fnstrGetFileNameFromFullName = Mid$(strFullName, bytPosPathSep + 1)
        Case 1 To 3
            'the likelihood of a filename len being less than 4 is *extremely unlikely* to occur in the real world
            'this is almost certainly a drive
        Case Else
            'probably Null or vbnullstring
        End Select
    End Function
    
    Public Function fnstrGetFileExtFromFileName(ByRef strFileName As String, _
                                                Optional ByVal blnRemoveMultiExt As Boolean) As String
        Dim bytPosExtSep As Byte
        Dim bytPosPathSep As Byte
    
        If Not Len(strFileName) > 0 Then
            Exit Function
        End If
    
        If blnRemoveMultiExt Then
            bytPosPathSep = InStrRev(strFileName, Application.PathSeparator)
            'dont detect "." in the path section
            bytPosExtSep = InStr(bytPosPathSep + 1, strFileName, ".")
        Else
            bytPosExtSep = InStrRev(strFileName, ".", -1)
        End If
    
        If bytPosExtSep > 0 Then
            fnstrGetFileExtFromFileName = Right$(strFileName, Len(strFileName) - bytPosExtSep)
        End If
    End Function
    
    
    Public Function fnstrRemoveFileExtFromFileName(ByVal strFileName As String, _
                                                    Optional ByVal blnRemoveMultiExt As Boolean) As String
        Dim strExt As String
        Dim bytPos As Byte
    
        If Not Len(strFileName) > 0 Then
            Exit Function
        End If
    
        strExt = "." & fnstrGetFileExtFromFileName(strFileName, blnRemoveMultiExt)
    
        bytPos = InStrRev(strFileName, strExt)
        If bytPos > 0 Then
            fnstrRemoveFileExtFromFileName = Left$(strFileName, bytPos - 1)
        Else
            fnstrRemoveFileExtFromFileName = strFileName
        End If
    End Function

  10. #10
    Forum Expert shg's Avatar
    Join Date
    06-20-2007
    Location
    The Great State of Texas
    MS-Off Ver
    2010, 2019
    Posts
    40,689

    Re: File & Folder Names Functions - Back to Basics

    never mind ...
    Last edited by shg; 11-18-2014 at 02:38 AM.

  11. #11
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    Re: File & Folder Names Functions - Back to Basics

    With the single exception of tightening a single character input in one of the functions (UPDATE: now solved), I think that I now have it as accurate as it can possibly be.

    Please note that since we are acting from the strings alone and without Dir/FSO access to the original files/paths, it is simply not possible to programatically determine the difference between:
    1. a FileName/FullName without a FileExtension
    2. a Path without a trailing Path Separator

    I have tried to minimise this risk by adding an optional boolean argument which allows the end user to choose which of the above two they want to err towards.

    The functions are provided for anyone to use if they want.

    Any feedback (good or bad!) is welcome.

    Private Sub DevTestFileNameFunctions()
    '/ this procedure for testing the file/folder name functions
        Const strcDRIVE As String = "C:"
        Const strcPATH1 As String = "path1"
        Const strcPATH2 As String = "path2"
        Const strcFNAME As String = "filename"
        Const strcEXT1 As String = "ext1"
        Const strcEXT2 As String = "ext2"
        Const strcSEP_PATH As String = "\"
        Const strcSEP_EXT As String = "."
    
        Dim avarTestFileFolders() As Variant
        Dim abytLoop As Byte
        Dim strOutput As String
        Dim strInput As String
    
        ReDim avarTestFileFolders(1 To 15)
        avarTestFileFolders(1) = strcDRIVE
        avarTestFileFolders(2) = strcDRIVE & strcSEP_PATH
        avarTestFileFolders(3) = strcDRIVE & strcSEP_PATH & strcPATH1
        avarTestFileFolders(4) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH
        avarTestFileFolders(5) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2
        avarTestFileFolders(6) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH
        avarTestFileFolders(7) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & _
            strcFNAME
        avarTestFileFolders(8) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & _
            strcFNAME & strcSEP_EXT & strcEXT1
        avarTestFileFolders(9) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_PATH & strcPATH2 & strcSEP_PATH & _
            strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
        avarTestFileFolders(10) = strcDRIVE & strcSEP_PATH & strcPATH1 & strcSEP_EXT & strcPATH2 & strcSEP_PATH & _
            strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
        avarTestFileFolders(11) = ""
        avarTestFileFolders(12) = Empty
        avarTestFileFolders(13) = strcFNAME
        avarTestFileFolders(14) = strcFNAME & strcSEP_EXT & strcEXT1
        avarTestFileFolders(15) = strcFNAME & strcSEP_EXT & strcEXT1 & strcSEP_EXT & strcEXT2
    
        Debug.Print Now() & vbTab & "test started"
    
        For abytLoop = LBound(avarTestFileFolders) To UBound(avarTestFileFolders)
    
            strOutput = vbNullString
            strInput = vbNullString
            strInput = (avarTestFileFolders(abytLoop))
    
            strOutput = fnstrGetFileNameFromString(strInput, True)
    
    'RESULTS:
    '
    ' fnstrGetPathFromString(False)
    '   FAILED = 7 (FullName w/o FileExt is assumed to be a Path w/o trailing Path Sep)
    '
    ' fnstrGetPathFromString(True)
    '   FAILED = 3 & 5 (Paths w/o trailing Path Sep are assumed to be a FullName w/o FileExt)
    '
    ' fnstrGetFileNameFromString(False)
    '   FAILED = 7 & 13 (FileName/FullName w/o FileExt is assumed to be a Path w/o trailing Path Sep)
    '
    ' fnstrGetFileNameFromString(True)
    '   FAILED = 3 & 5 (Paths w/o trailing Path Sep are assumed to be a FileName/FullName w/o FileExt)
    '
    ' fnstrGetFileExtFromString(True or False)
    '   ALL PASSED!
    '
    
            Debug.Print Format(abytLoop, "00") & Space(2) & "READ: " & strOutput & Space(35 - Len(strOutput)) & _
                vbTab & "FROM: " & avarTestFileFolders(abytLoop)
        Next abytLoop
    
        Debug.Print Now() & vbTab & "test completed"
    End Sub
    
    Public Function fnstrGetSeparatoredPath(ByRef strPath As String) As String
    '/ doesn't detect garbage input, requires a Path arg
    '/ ensures folder path ends in path separator
        If Not Len(strPath) > 0 Then
            Exit Function
        End If
    
        With Application
            If Right$(strPath, 1) = .PathSeparator Then
                fnstrGetSeparatoredPath = strPath
            Else
                fnstrGetSeparatoredPath = strPath & .PathSeparator
            End If
        End With
    End Function
    
    Public Function fnstrGetPathFromString(ByRef strFullName As String, _
                                        Optional ByVal blnAllowFilesWithOutExts As Boolean) As String
        Dim strResult As String
    
        'remove any leading/trailing spaces
        strFullName = Trim(strFullName)
    
        Select Case Len(strFullName)
        Case Is > 3
            If Mid$(strFullName, 2, 2) = ":\" Then
                'arg has drive prefix
            ElseIf Left$(strFullName, 2) = "\\" Then
                'arg is UNC
            Else
                'arg = FileName or garbage
                GoTo ExitProcedure
            End If
    
            'therefore arg = Path or FullName
    
            If Right$(strFullName, 1) = "\" Then
                'arg = Path
                strResult = strFullName
            ElseIf InStr(InStrRev(strFullName, "\"), strFullName, ".") > 0 Then
                'a FileExt was found after last Path Sep therefore arg = FullName
                strResult = Left$(strFullName, InStrRev(strFullName, "\"))
            Else
                'arg = FullName (w/o Ext) or Path (w/o trailing Path Sep)
    
                If blnAllowFilesWithOutExts Then
                    'the opt. bln arg set means assume arg = FullName w/o Ext
                    strResult = Left$(strFullName, InStrRev(strFullName, "\"))
                Else
                    'the opt. bln arg set means assume arg = Path w/o trailing Path Sep
                    strResult = strFullName
                End If
            End If
        Case 1 To 3
            'the likelihood of a FileName len being less than 4 is *extremely unlikely* to occur in the Real World
            'therefore the arg is almost certainly a drive (or garbage)
            If Len(strFullName) > 1 Then
                If Not Mid$(strFullName, 2, 1) = ":" Then
                    'no drive found therefore arg = garbage
                    GoTo ExitProcedure
                Else
                    strResult = strFullName
                End If
            Else
                Select Case Asc(UCase(strFullName))
                Case 65 To 90
                    strResult = UCase(strFullName) & ":"
                Case Else
                    'arg = garbage
                End Select
            End If
        Case Else
            'probably Null or vbnullstring
        End Select
    
    ExitProcedure:
        fnstrGetPathFromString = strResult
    End Function
    
    Public Function fnstrGetFileNameFromString(ByRef strFullName As String, _
                                                Optional ByVal blnAllowFilesWithOutExts As Boolean) As String
    '/ Paths without a trailing Path Separator can be mistaken for FullNames w/o File Exts
    '/ added optional boolean arg so end user can choose which one they want to err towards
    
        Dim bytPosPathSep As Byte
    
        'remove any leading/trailing spaces
        strFullName = Trim(strFullName)
    
        Select Case Len(strFullName)
        Case Is > 3
            If blnAllowFilesWithOutExts = False Then
                'this optional arg has good & bad points
                'good = ignores garbage input
                'bad = overlooks any file missing ext
                If Not InStr(strFullName, ".") > 0 Then
                    Exit Function
                End If
            End If
    
            bytPosPathSep = InStrRev(strFullName, Application.PathSeparator)
    
            fnstrGetFileNameFromString = Mid$(strFullName, bytPosPathSep + 1)
        Case 1 To 3
            'the likelihood of a filename len being less than 4 is *extremely unlikely* to occur in the real world
            'this is almost certainly a drive or garbage
        Case Else
            'probably Null or vbnullstring
        End Select
    End Function
    
    Public Function fnstrGetFileExtFromString(ByRef strFileName As String, _
                                        Optional ByVal blnRemoveMultiExt As Boolean) As String
        Dim bytPosExtSep As Byte
        Dim bytPosPathSep As Byte
    
        'remove any leading/trailing spaces
        strFileName = Trim(strFileName)
    
        If Not Len(strFileName) > 0 Then
            Exit Function
        End If
    
        If blnRemoveMultiExt Then
            bytPosPathSep = InStrRev(strFileName, Application.PathSeparator)
            'dont detect "." in the path section
            bytPosExtSep = InStr(bytPosPathSep + 1, strFileName, ".")
        Else
            bytPosExtSep = InStrRev(strFileName, ".", -1)
        End If
    
        If bytPosExtSep > 0 Then
            fnstrGetFileExtFromString = Right$(strFileName, Len(strFileName) - bytPosExtSep)
        End If
    End Function
    
    Public Function fnstrRemoveFileExtFromString(ByRef strFileName As String, _
                                        Optional ByVal blnRemoveMultiExt As Boolean) As String
        Dim strExt As String
        Dim bytPos As Byte
    
        'remove any leading/trailing spaces
        strFileName = Trim(strFileName)
    
        If Not Len(strFileName) > 0 Then
            Exit Function
        End If
    
        strExt = "." & fnstrGetFileExtFromString(strFileName, blnRemoveMultiExt)
    
        bytPos = InStrRev(strFileName, strExt)
        If bytPos > 0 Then
            fnstrRemoveFileExtFromString = Left$(strFileName, bytPos - 1)
        Else
            fnstrRemoveFileExtFromString = strFileName
        End If
    End Function
    
    Public Function fnstrRemoveInvalidCharsFromFileName(ByVal strFileName As String) As String
        Dim strNewString As String
        strNewString = Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(strFileName, "|", _
            ""), ">", ""), "<", ""), Chr(34), ""), "?", ""), "*", ""), ":", ""), "/", ""), "\", "")
        fnstrRemoveInvalidCharsFromFileName = strNewString
    End Function
    Last edited by mc84excel; 11-18-2014 at 07:30 PM. Reason: edited code to add solved function

  12. #12
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    Re: File & Folder Names Functions - Back to Basics

    Quote Originally Posted by mc84excel View Post
    With the single exception of tightening a single character input in one of the functions (UPDATE: now solved), I think that I now have it as accurate as it can possibly be.
    Famous last words.

    I have recently encountered some real-life examples of file names that are not handled correctly by these functions. I will reopen this thread until I solve them.

    SCENARIO 1:
    Copy this into the Immediate Window. It will give the wrong result. The test filename used explains why.
    ? fnstrRemoveFileExtFromString("Mr.Surname_SomeFileNamesContainFullStopsForAbbreviationsEtc.FileExt",True)

    SCENARIO 2:
    Copy this into the Immediate Window. It will give the wrong result. The test filename used explains why.
    ? fnstrRemoveFileExtFromString("SomeFileNamesContainVersionNumbers_v1.1.FileExt",True)
    Both the above examples will return the correct result if we ignore the optional boolean argument "blnRemoveMultiExt".
    However doing this creates a problem when a filename contains a fullstop as well as multiple file extensions.


    A quick explanation on the concept of multiple file extensions.
    Some programs create output files with a file extension that has more than one full stop. e.g. FileName.001.FileExt, FileName.002.FileExt etc.
    In these cases, the end user may want to return "FileName" instead of "FileName.001" etc.
    These are what I call multiple File Extensions (if anyone can suggest a better descriptive name and/or a clearer explanation of this concept I would be grateful)


    Thoughts on possible solutions
    As stated before, these functions can only use the file/folder strings only - the files may not be on the computer we run the code on so we cant make use of FSO. This makes the whole exercise very challenging.

    Example 2 - I could try using MID to check backwards 1 or 2 characters from the fullstop position = "v"/"ver"/"ver."/"v."

    Example 1 - I could try to set a maximum limit on the len of each expected file extension. E.g. if the full stop is more than 5 characters from the previous full stop then it is assumed that this section is not part of a multiple File Extension

  13. #13
    Valued Forum Contributor
    Join Date
    08-29-2012
    Location
    In lockdown
    MS-Off Ver
    Excel 2010 (2003 to 2016 but 2010 for choice)
    Posts
    1,766

    Re: File & Folder Names Functions - Back to Basics

    Discovered an error recently - I had the boolean argument around the wrong way. Updated function below:

    Public Function fnstrGetFileExtFromString(ByRef strFileName As String, _
                                        Optional ByVal blnDetectMultiExt As Boolean) As String
        Dim bytPosExtSep As Byte
        Dim bytPosPathSep As Byte
    
        'remove any leading/trailing spaces
        strFileName = Trim(strFileName)
    
        If Not Len(strFileName) > 0 Then
            Exit Function
        End If
    
        If blnDetectMultiExt Then
            bytPosPathSep = InStrRev(strFileName, Application.PathSeparator)
            'dont detect "." in the path section
            bytPosExtSep = InStr(bytPosPathSep + 1, strFileName, ".")
        Else
            bytPosExtSep = InStrRev(strFileName, ".", -1)
        End If
    
        If bytPosExtSep > 0 Then
            fnstrGetFileExtFromString = Right$(strFileName, Len(strFileName) - bytPosExtSep)
        End If
    End Function

+ Reply to Thread

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. Replies: 15
    Last Post: 08-27-2012, 10:13 AM
  2. [SOLVED] Macro to copy file names and data from each file in a folder into master spreadsheet
    By dee1989 in forum Excel Programming / VBA / Macros
    Replies: 11
    Last Post: 07-10-2012, 05:52 AM
  3. Replies: 3
    Last Post: 08-21-2011, 07:55 PM
  4. Replies: 0
    Last Post: 08-21-2011, 07:38 AM
  5. read in folder names and file names
    By gshock in forum Excel Programming / VBA / Macros
    Replies: 2
    Last Post: 03-11-2011, 12:45 PM

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts

Search Engine Friendly URLs by vBSEO 3.6.0 RC 1