2013-05-17 2 views
1

В C/C++, как я могу извлечь из c:\Blabla - dsf\blup\AAA - BBB\blabla.bmp подстроки AAA и BBB?Извлечь подстроки имени файла

i.e извлеките детали до и после - в последней папке с именем файла.

Заранее спасибо.

(PS: если это возможно, без платформы .NET или такие вещи, в которых я мог бы легко запутаться)

+0

Это может быть хороший случай для использования обычные выражения... – nabulke

ответ

1

Равнина C++ решение (без наддува, ни C++ 11), до сих пор регулярное выражение решение Джеймса 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; 
} 
+0

спасибо! мне действительно нужно 'trim', если я хочу извлечь то, что есть до и после' - '(<->)? Если мы ищем '-', действительно ли нужно обрезать? – Basj

+1

Нет, вам не нужно. Поэтому вы можете устранить «Trim» (вызовы и обработку). – Liviu

2

Использование станд :: строка RFIND rfind (char c, size_t pos = npos)

  1. Найти символ '\' из конец с использованием rfind (pos1)
  2. Найти следующий символ '\' используя rfind (pos2)
  3. Получите подстроку между позициями pos2 и pos1. Для этого используйте функцию подстроки.
  4. Поиск символа '-' (POS3)
  5. Extract 2 подстроки между POS3 и POS1, POS3 и Pos2
  6. Удалите пробелы в подстроки.

Итоговые подстроки будет AAA и BBB

+0

Хорошее решение. Возможно, было бы легче извлечь подстроки без пробелов. – gkovacs90

+0

@gkovacs: если мы знаем, что текстовым форматом всегда будет слово - слово, тогда мы можем уменьшить/увеличить позицию при извлечении подстрок, что означает без пробелов. – bjskishore123

+1

Да, это именно то, что я говорю, поэтому нет необходимости в шаге 6 в вашем algrithm. Это можно решить одним утверждением. Но это всего лишь небольшая коррекция, ваше решение работает хорошо. – gkovacs90

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.

+0

А что такое 'PathRemoveFileSpec'? Это нужно также написать. –

+0

@JamesKanze - http://msdn.microsoft.com/en-us/library/windows/desktop/bb773748%28v=vs.85%29.aspx – user93353

+0

Очень полезно, если вы не под Windows. (Даже под Windows, нет причин быть не переносимыми здесь.) –

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; 
} 
+1

Хороший пример _why_ мы не используем plain C. –

+0

@James Kanze Перед тем, как быть умным (C++/C#), вам нужно знать обычное C. Возможно, это домашнее задание. – Liviu

+0

Это абсолютно неверно. Вы не должны начинать с простого C перед изучением C++; это будет только путаницей. –

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, раскол , который может разделяться в соответствии с регулярным выражением, обрезка которой может быть передана предикату, определяющая, что должно быть trimm ed и т. д.)

В любом случае, применение split и trim должно быть очевидно , чтобы предоставить вам то, что вы хотите.

+0

Спасибо за ваш ответ! Я использую Visual C++ 2010 express, поэтому у меня, вероятно, нет C++ 11? Что мне нужно сделать? Я забыл спросить: что произойдет, если: а) есть много вхождений '-' в имя последней папки? б) в последнем имени папки нет вхождения '-'? – Basj

+0

Если у вас нет C++ 11, всегда есть boost :: regex. И 'split' и' trim' не требуют C++ 11. Что касается того, что произойдет, если существует различное количество событий '-': это зависит. С регулярным выражением, которое я представляю, совпадения не будет, поэтому вы не пойдете в 'if'. Используя 'split' и' trim', это зависит от вас; когда вы выполняете второй 'split' (на' '-''), вы получите еще одно поле, чем' '-''. –

Смежные вопросы