2011-09-09 82 views
0

我有一个文件路径,从__FILE__宏获得,我想从中提取2个文件。获取文件路径的部分

格式为:/some/path/to/a/file/AAA/xxx/BBB.cc。我想要AAABBB的路径。 xxx通常是src,inc,tst等,文件扩展名一般是.cc,但不能保证。

我知道我可以使用string.find()甚至将字符串拆分为/字符的数组,但是由于需要搜索的次数,这两个字符都不是很有效。我想到了sscanf,并认为这可能是最好的方法,但是,我一直无法定义格式,以至于它会跳过大部分开始并获得我需要的部分。我如何使用sscanf来做到这一点,还是有更好的方法?

感谢您的帮助。

+0

您是否尝试过使用['strtok()'](http://www.cplusplus.com/reference/clibrary/cstring/strtok/)? – Kusalananda

+0

@KAK'strtok'是我尽可能避免它的最有缺陷的c函数之一。 – CodesInChaos

+0

@CodeInChaos,为什么? – Kusalananda

回答

2

使用rfind,这样就可以在年底开始和向后工作:

string s = "/some/path/to/a/file/AAA/xxx/BBB.cc"; 

unsigned int a = s.rfind('.'); 
unsigned int b = s.rfind('/'); 
string BBB = s.substr(b+1,a-b-1); 

a = s.rfind('/',b-1); 
b = s.rfind('/',a-1); 
string AAA = s.substr(b+1,a-b-1); 
0
  1. 做正确的事
  2. 如果它不够快,提高它

很容易只是自己写这不是试图让sscanf会做到这一点。你的代码会更容易理解,并且速度更快(但是,我怀疑这很重要)。

只是从字符串的后面循环。当找到第一个点时,请记住该位置,然后在找到第一个斜线时提取BBB。记住第二个斜线的位置,并在找到第三个斜线时提取AAA。

+1

这种事情通常是这么做的,所以找到一个标准的解决方案(比如使用'strtok()')比自己编写代码更好,并且可能会弄巧成拙。这不是它。 – Kusalananda

+1

除了'strtok'不是一个很漂亮的函数(需要销毁源字符串 - 所以如果你有一个字符串字面值,你需要将它复制到其他地方 - 并且是不可重入的),它可以很好地从左到右扫描,但如果我理解正确,他需要从右向左扫描。 –

0
char *path = ... /* fill this however you like, for example function argument */ 
char *AAA_start, *AAA_end; 
char *BBB_start, *BBB_end; 
     // go the end of the string and find the first . 
for (BBB_end = path+strlen(path); *BBB_end != '.'; --BBB_end); 
     // continue to find the first/
for (BBB_start = BBB_end; *BBB_start != '/'; --BBB_start); 
     // Now you have the beginning and end of BBB 
     // continue from there to find next/
for (AAA_end = BBB_start-1; *AAA_end != '/'; --AAA_end); 
     // continue from there to find next/
for (AAA_start = AAA_end-1; *AAA_start != '/'; --AAA_start); 
     // Now you have the beginning and end of AAA 

     // Now you can do whatever you want with AAA and BBB, for example 
char *AAA = new char[AAA_end-AAA_start+2]; // AAA_end is included in the result 
              // hence +1. Another +1 for the NULL 
char *BBB = new char[BBB_end-BBB_start+2]; 
memcpy(AAA, AAA_start, AAA_end-AAA_start+1); 
memcpy(BBB, BBB_start, BBB_end-BBB_start+1); 
AAA[AAA_end-AAA_start+1] = NULL; 
BBB[BBB_end-BBB_start+1] = NULL; 

这是基本的想法。现在,你需要添加错误检查到这一点:

char *path = ... /* fill this however you like, for example function argument */ 
char *AAA_start, *AAA_end; 
char *BBB_start, *BBB_end; 
for (BBB_end = path+strlen(path); *BBB_end != '.' && BBB_end != path; --BBB_end); 
if (BBB_end == path) return FAIL; 
for (BBB_start = BBB_end; *BBB_start != '/' && BBB_start != path; --BBB_start); 
if (BBB_start == path) return FAIL; 
for (AAA_end = BBB_start-1; *AAA_end != '/' && AAA_end != path; --AAA_end); 
if (AAA_end == path) return FAIL; 
for (AAA_start = AAA_end-1; *AAA_start != '/' && AAA_start != path; --AAA_start); 
if (AAA_start == path && *AAA_start != '/') return FAIL; 

char *AAA = new char[AAA_end-AAA_start+2]; 
char *BBB = new char[BBB_end-BBB_start+2]; 
memcpy(AAA, AAA_start, AAA_end-AAA_start+1); 
memcpy(BBB, BBB_start, BBB_end-BBB_start+1); 
AAA[AAA_end-AAA_start+1] = NULL; 
BBB[BBB_end-BBB_start+1] = NULL; 
+0

如果'path'没有正确的格式,这段代码将会在字符串的开头之外读取,因此会显示未定义的行为。更健壮一点也不错。 – CodesInChaos

+0

@CodeInChaos,我不想让错误检查臃肿的代码,所以OP不会错过这一点。无论哪种方式,我都会更新答案。 – Shahbaz

+0

发布非生产就绪代码是很好的IMO。但是,答案应该指出缺陷,以便用户知道他应该改变而不是仅仅复制粘贴。就我个人而言,我会实现一个类似于'rfind'的帮助函数,因为这段代码有点难以阅读。 – CodesInChaos

0

正则表达式可以做的伎俩:

#include <boost/regex.hpp> 
#include <iostream> 
#include <cstdlib> 

int main() { 
    std::string path("/some/path/to/a/file/AAA/xxx/BBB.cc"); 

    boost::regex path_re(".+/([^/]+)/[^/]+/([^.]+)\\.(.+?)", boost::regex::perl); 
    boost::smatch m; 
    if(regex_match(path, m, path_re)) { 
     std::cout << "part 1 " << m[1] << '\n'; 
     std::cout << "part 2 " << m[2] << '\n'; 
     std::cout << "part 3 " << m[3] << '\n'; 
    } 
    else { 
     abort(); 
    } 
} 

输出:

part 1 AAA 
part 2 BBB 
part 3 cc 

注意,它不处理非 - 正则路径,其中包含/./个元素。