使用 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