使用 c++ 解析路径

使用 c++ 解析路径

以下函数实现: 从输入字符串中获取路径,目录,文件名,纯文件名(无扩展名),扩展名。

测试代码和源码可点此处下载。

头文件

#ifndef _UTILS_PATH_H_
#define _UTILS_PATH_H_

#include <string>

std::string UtilsGetPath( const char *pszFilename );
std::string UtilsGetDirname( const char *pszFilename );
std::string UtilsGetFilename( const char *pszFullFilename );
std::string UtilsGetBasename( const char *pszFullFilename );
std::string UtilsGetExtension( const char *pszFullFilename );

#endif

源文件

#include <cstring>
#include <string>

using namespace std;

/************************************************************************/
/*                        UtilsFindFilenameStart()                        */
/************************************************************************/

static int UtilsFindFilenameStart( const char * pszFilename )

{
    size_t iFileStart = strlen(pszFilename);

    for( ;
         iFileStart > 0
             && pszFilename[iFileStart-1] != '/'
             && pszFilename[iFileStart-1] != '\\';
         iFileStart-- ) {}

    return static_cast<int>( iFileStart );
}


/************************************************************************/
/*                             UtilsGetPath()                             */
/************************************************************************/

/**
 * Extract directory path portion of filename.
 *
 * Returns a string containing the directory path portion of the passed
 * filename.  If there is no path in the passed filename an empty string
 * will be returned (not NULL).
 *
 * <pre>
 * UtilsGetPath( "abc/def.xyz" ) == "abc"
 * UtilsGetPath( "/abc/def/" ) == "/abc/def"
 * UtilsGetPath( "/" ) == "/"
 * UtilsGetPath( "/abc/def" ) == "/abc"
 * UtilsGetPath( "abc" ) == ""
 * </pre>
 *
 * @param pszFilename the filename potentially including a path.
 *
 *  @return Path in an internal string which must not be freed.  The string
 * may be destroyed by the next CPL filename handling call.  The returned
 * will generally not contain a trailing path separator.
 */
string UtilsGetPath( const char *pszFilename )
{
    const int iFileStart = UtilsFindFilenameStart(pszFilename);
    if (iFileStart == 0) return "";
    return string(pszFilename, pszFilename+iFileStart-1);
}


/************************************************************************/
/*                             UtilsGetDirname()                          */
/************************************************************************/

/**
 * Extract directory path portion of filename.
 *
 * Returns a string containing the directory path portion of the passed
 * filename.  If there is no path in the passed filename the dot will be
 * returned.  It is the only difference from UtilsGetPath().
 *
 * <pre>
 * UtilsGetDirname( "abc/def.xyz" ) == "abc"
 * UtilsGetDirname( "/abc/def/" ) == "/abc/def"
 * UtilsGetDirname( "/" ) == "/"
 * UtilsGetDirname( "/abc/def" ) == "/abc"
 * UtilsGetDirname( "abc" ) == "."
 * </pre>
 *
 * @param pszFilename the filename potentially including a path.
 *
 * @return Path in an internal string which must not be freed.  The string
 * may be destroyed by the next CPL filename handling call.  The returned
 * will generally not contain a trailing path separator.
 */
string UtilsGetDirname( const char *pszFilename )
{
    const int iFileStart = UtilsFindFilenameStart(pszFilename);
    if (iFileStart == 0) return ".";
    return string(pszFilename, pszFilename+iFileStart-1);
}


/************************************************************************/
/*                           UtilsGetFilename()                           */
/************************************************************************/

/**
 * Extract non-directory portion of filename.
 *
 * Returns a string containing the bare filename portion of the passed
 * filename.  If there is no filename (passed value ends in trailing directory
 * separator) an empty string is returned.
 *
 * <pre>
 * UtilsGetFilename( "abc/def.xyz" ) == "def.xyz"
 * UtilsGetFilename( "/abc/def/" ) == ""
 * UtilsGetFilename( "abc/def" ) == "def"
 * </pre>
 *
 * @param pszFullFilename the full filename potentially including a path.
 *
 * @return just the non-directory portion of the path (points back into
 * original string).
 */

string UtilsGetFilename( const char *pszFullFilename )
{
    const int iLen = static_cast<int>(strlen(pszFullFilename));
    const int iFileStart = UtilsFindFilenameStart( pszFullFilename );
    return string(pszFullFilename+iFileStart, pszFullFilename+iLen);
}

/************************************************************************/
/*                           UtilsGetBasename()                           */
/************************************************************************/

/**
 * Extract basename (non-directory, non-extension) portion of filename.
 *
 * Returns a string containing the file basename portion of the passed
 * name.  If there is no basename (passed value ends in trailing directory
 * separator, or filename starts with a dot) an empty string is returned.
 *
 * <pre>
 * UtilsGetBasename( "abc/def.xyz" ) == "def"
 * UtilsGetBasename( "abc/def" ) == "def"
 * UtilsGetBasename( "abc/def/" ) == ""
 * </pre>
 *
 * @param pszFullFilename the full filename potentially including a path.
 *
 * @return just the non-directory, non-extension portion of the path in
 * an internal string which must not be freed.  The string
 * may be destroyed by the next CPL filename handling call.
 */

string UtilsGetBasename( const char *pszFullFilename )
{
    const size_t iFileStart = static_cast<size_t>( UtilsFindFilenameStart( pszFullFilename ) );
    size_t iExtStart = strlen(pszFullFilename);
    for (; 
         iExtStart > iFileStart && pszFullFilename[iExtStart] != '.';
         iExtStart-- ) {}
    if (iExtStart == iFileStart) iExtStart = strlen(pszFullFilename);
    return string(pszFullFilename+static_cast<int>(iFileStart), 
                  pszFullFilename+static_cast<int>(iExtStart));
}


/************************************************************************/
/*                           UtilsGetExtension()                          */
/************************************************************************/

/**
 * Extract filename extension from full filename.
 *
 * Returns a string containing the extension portion of the passed
 * name.  If there is no extension (the filename has no dot) an empty string
 * is returned.  The returned extension will not include the period.
 *
 * <pre>
 * UtilsGetExtension( "abc/def.xyz" ) == "xyz"
 * UtilsGetExtension( "abc/def" ) == ""
 * </pre>
 *
 * @param pszFullFilename the full filename potentially including a path.
 *
 * @return just the extension portion of the path in
 * an internal string which must not be freed.  The string
 * may be destroyed by the next CPL filename handling call.
 */
string UtilsGetExtension( const char *pszFullFilename )
{
    if (pszFullFilename[0] == '\0') return "";
    size_t iFileStart = static_cast<size_t>( UtilsFindFilenameStart( pszFullFilename ) );
    size_t sLen = strlen(pszFullFilename);
    size_t iExtStart = strlen(pszFullFilename);
    for ( ;
         iExtStart > iFileStart && pszFullFilename[iExtStart] != '.';
         iExtStart-- ) {}
    if (iExtStart == iFileStart)
        return "";
    // If the extension is too long, it is very much likely not an extension,
    // but another component of the path
    const size_t knMaxExtensionSize = 10;
    if (sLen - iExtStart > knMaxExtensionSize) {
        return "";
    }
    return string(iExtStart+1+pszFullFilename, pszFullFilename+sLen);
}

测试结果

1: >>> /abc/def.xyz
1:      Path: /abc
1:       dir: /abc
1:   filname: def.xyz
1:  basename: def
1: extension: xyz
1/6 Test #1: Runs1 ............................   Passed    0.01 sec

2: >>> /abc/def/
2:      Path: /abc/def
2:       dir: /abc/def
2:   filname:
2:  basename:
2: extension:
2/6 Test #2: Runs2 ............................   Passed    0.01 sec
test 3
    Start 3: Runs3

3: >>> /abc/def
3:      Path: /abc
3:       dir: /abc
3:   filname: def
3:  basename: def
3: extension:
3/6 Test #3: Runs3 ............................   Passed    0.01 sec
test 4
    Start 4: Runs4

4: >>> /abc
4:      Path:
4:       dir:
4:   filname: abc
4:  basename: abc
4: extension:
4/6 Test #4: Runs4 ............................   Passed    0.01 sec

5: >>> abc
5:      Path:
5:       dir: .
5:   filname: abc
5:  basename: abc
5: extension:
5/6 Test #5: Runs5 ............................   Passed    0.01 sec
test 6
    Start 6: Runs6

6: >>> /
6:      Path:
6:       dir:
6:   filname:
6:  basename:
6: extension:
6/6 Test #6: Runs6 ............................   Passed    0.01 sec
posted @ 2022-07-26 09:44  Wreng  阅读(219)  评论(0编辑  收藏  举报