提取文件名的子字符串

时间:2013-05-17 08:11:20

标签: c++ windows string substring

在C / C ++中,如何从c:\Blabla - dsf\blup\AAA - BBB\blabla.bmp中提取子串AAABBB

即。在文件名的最后一个文件夹中提取-之前和之后的部分。

提前致谢。

(PS:如果可能的话,没有Framework .net或者其他我很容易迷失的东西)

5 个答案:

答案 0 :(得分:2)

使用std :: string rfind rfind (char c, size_t pos = npos)

  1. 使用rfind(pos1)
  2. 从最后找到字符'\'
  3. 使用rfind(pos2)
  4. 查找下一个字符'\'
  5. 获取位置pos2和pos1之间的子串。使用子字符串函数。
  6. 找到字符' - '(pos3)
  7. 在pos3和pos1,pos3和pos2
  8. 之间提取2个子串
  9. 删除子字符串中的空格。
  10. 产生的子串将是AAA和BBB

答案 1 :(得分:2)

#include <iostream>
using namespace std;

#include <windows.h>
#include <Shlwapi.h> // link with shlwapi.lib

int main()
{
    char buffer_1[ ] = "c:\\Blabla - dsf\\blup\\AAA - BBB\\blabla.bmp"; 
    char *lpStr1 = buffer_1;

    // Remove the file name from the string
    PathRemoveFileSpec(lpStr1);
    string s(lpStr1);

    // Find the last directory name
    stringstream ss(s.substr(s.rfind('\\') + 1));

   // Split the last directory name into tokens separated by '-'
    while (getline(ss, s, '-')) 
        cout << s << endl;
}

评论中的解释。

这不会修剪前导空格 - 在输出中 - 如果您还想这样做 - 请检查this

答案 2 :(得分:2)

这包括普通C中的所有工作和验证:

int FindParts(const char* source, char** firstOut, char** secondOut)
{
const char* last        = NULL;
const char* previous    = NULL;
const char* middle      = NULL;
const char* middle1     = NULL;
const char* middle2     = NULL;
char* first;
char* second;

last = strrchr(source, '\\');
if (!last || (last  == source))
    return -1;
--last;
if (last == source)
    return -1;

previous = last;
for (; (previous != source) && (*previous != '\\'); --previous);
++previous;

{
    middle = strchr(previous, '-');
    if (!middle || (middle > last))
        return -1;

    middle1 = middle-1;
    middle2 = middle+1;
}

//  now skip spaces

for (; (previous != middle1) && (*previous == ' '); ++previous);
if (previous == middle1)
    return -1;
for (; (middle1 != previous) && (*middle1 == ' '); --middle1);
if (middle1 == previous)
    return -1;
for (; (middle2 != last) && (*middle2 == ' '); ++middle2);
if (middle2 == last)
    return -1;
for (; (middle2 != last) && (*last == ' '); --last);
if (middle2 == last)
    return -1;

first   = (char*)malloc(middle1-previous+1 + 1);
second  = (char*)malloc(last-middle2+1 + 1);
if (!first || !second)
{
    free(first);
    free(second);
    return -1;
}

strncpy(first, previous, middle1-previous+1);
first[middle1-previous+1] = '\0';
strncpy(second, middle2, last-middle2+1);
second[last-middle2+1] = '\0';

*firstOut   = first;
*secondOut  = second;

return 1;
}

答案 3 :(得分:2)

使用正则表达式可以相对容易地完成: std::regex如果你有C ++ 11; boost::regex如果你不这样做:

static std::regex( R"(.*\\(\w+)\s*-\s*(\w+)\\[^\\]*$" );
smatch results;
if ( std::regex_match( path, results, regex ) ) {
    std::string firstMatch = results[1];
    std::string secondMatch = results[2];
    //  ...
}

此外,你绝对应该拥有split和 工具箱中的trim

template <std::ctype_base::mask test>
class IsNot
{
    std::locale ensureLifetime;
    std::ctype<char> const* ctype;  //  Pointer to allow assignment
public:
    Is( std::locale const& loc = std::locale() )
        : ensureLifetime( loc )
        , ctype( &std::use_facet<std::ctype<char>>( loc ) )
    {
    }
    bool operator()( char ch ) const
    {
        return !ctype->is( test, ch );
    }
};
typedef IsNot<std::ctype_base::space> IsNotSpace;

std::vector<std::string>
split( std::string const& original, char separator )
{
    std::vector<std::string> results;
    std::string::const_iterator current = original.begin();
    std::string::const_iterator end = original.end();
    std::string::const_iterator next = std::find( current, end, separator );
    while ( next != end ) {
        results.push_back( std::string( current, next ) );
        current = next + 1;
        next = std::find( current, end, separator );
    }
    results.push_back( std::string( current, next ) );
    return results;
}

std::string
trim( std::string const& original )
{
    std::string::const_iterator end
        = std::find_if( original.rbegin(), original.rend(), IsNotSpace() ).base();
    std::string::const_iterator begin
        = std::find_if( original.begin(), end, IsNotSpace() );
    return std::string( begin, end );
}

(这些只是你在这里需要的。你显然想要 完整的IsXxx和IsNotXxx谓词,分裂 可以根据正则表达式分割,修剪哪个 可以传递一个谓词对象来指定它是什么 修剪等。)

无论如何,splittrim的应用应该是显而易见的 给你你想要的东西。

答案 4 :(得分:1)

普通的C ++解决方案(没有boost,也没有C ++ 11),仍然是James Kanze(https://stackoverflow.com/a/16605408/1032277)的正则表达式解决方案是最通用和优雅的:

inline void Trim(std::string& source)
{
size_t position = source.find_first_not_of(" ");
if (std::string::npos != position)
    source = source.substr(position);
position = source.find_last_not_of(" ");
if (std::string::npos != position)
    source = source.substr(0, position+1);
}

inline bool FindParts(const std::string& source, std::string& first, std::string& second)
{
size_t last = source.find_last_of('\\');
if ((std::string::npos == last) || !last)
    return false;

size_t previous = source.find_last_of('\\', last-1);
if (std::string::npos == last)
    previous = -1;

size_t middle = source.find_first_of('-',1+previous);
if ((std::string::npos == middle) || (middle > last))
    return false;

first   = source.substr(1+previous, (middle-1)-(1+previous)+1);
second  = source.substr(1+middle, (last-1)-(1+middle)+1);

Trim(first);
Trim(second);

return true;
}