项目中要获取一个文件路径的文件名称,这让我想起了php中的basename()函数。于是看了php中的实现basename()函数的源码:
源码如下:
void php_basename(char *s, size_t len, char *suffix, size_t sufflen, char **p_ret, size_t *p_len)
{
char *ret = NULL, *c, *comp, *cend;
size_t inc_len, cnt;
int state;
c = comp = cend = s;
cnt = len;
state = 0;
while (cnt > 0) {
inc_len = 1;
if (*c == '/' || *c == '\\') {
if (state == 1) {
state = 0;
cend = c;
}
} else {
if (state == 0) {
comp = c;
state = 1;
}
}
c += inc_len;
cnt -= inc_len;
}
if (state == 1) {
cend = c;
}
if (suffix != NULL && sufflen < (size_t)(cend - comp) &&
memcmp(cend - sufflen, suffix, sufflen) == 0) {
cend -= sufflen;
}
len = cend - comp;
if (p_ret) {
ret = malloc(len + 1);
memcpy(ret, comp, len);
ret[len] = '\0';
*p_ret = ret;
}
if (p_len) {
*p_len = len;
}
}
/* }}} */
/* {{{ proto string basename(string path [, string suffix])
Returns the filename component of the path */
char *basename(char *string, char *suffix)
{
char *ret;
int string_len = strlen(string), suffix_len = strlen(suffix);
size_t ret_len;
php_basename(string, string_len, suffix, suffix_len, &ret, &ret_len);
return ret;
}
来源:http://demon.tw/programming/c-php-basename.html
这段代码刚开始看挺费劲,state从0变成1,又从1变成0,想了半天终于是弄清楚逻辑了。不由感叹这段代码的神奇,如同一幅太极图,你中有我,我中有你,相互呼应。
然而,这段代码感觉并不高效。我们传入的路径通常很长,比如下面这个路径:
/Users/Library/Developer/CoreSimulator/Devices/5FEEB80E-8EA7-4090-A943-C1C033671D54/data/Containers/Data/Application/E3F82D85-A99A-475C-A467-F999226F3235/app.html。上面这个代码从头开始遍历,边遍历边判断。而我们最后要的结果恰好是在最后,这也就带来了性能的浪费。在这样的情况下,我们完全可以倒着遍历字符串。如下代码所示
void baseNameHandle(char*s,char**p_ret)
{
char* _ret[30]={0};
int nLen=strlen(s);
int iPos=nLen-1;
while(s[iPos]!=’\\’&&pFilePath[iPos]!=’/’)
{
--iPos;
}
strncpy(_ret,s+iPos+1,nLen-iPos-1);
*p_ret=_ret;
}
上面的效率比较都是基于自我感觉的,更加严谨的比较需要通过测试。不过从代码可读性来说,自认为下面的代码更强一些,以后维护起来也方便