2017-06-12 121 views
0

我很好奇,如果有一個以前編寫的函數用於縮短c字符串中的文件路徑。縮短路徑字符串函數

例子:

char* filePath1 = "\\folder1\\..\\folder1\\file.dat"; 
char* filePath2 = "\\folder1\\folder2\\..\\..\\folder1\\file.dat"; 
char* filePath3 = "\\folder1\\folder3\\..\\folder2\\..\\folder1\\file.dat"; 

我想知道如果有能夠識別所有這些字符串的減少

char* allFilePaths = "\\folder1\\file.dat"; 

我沒有寄予厚望的功能,但如果有一種避免重寫現有(並且希望經過充分測試)代碼的方法,我完全贊成!

+1

請注意'\ f'是一個換頁。你可能打算每次使用'\\ f'。 –

+1

你想做文本替換還是需要驗證'folder2'和'fol​​der3'是否存在?系統驗證名稱,但涉及更多的工作而不是純文本替換。很可能有微軟的API函數來完成這項工作。我知道我有Unix的類似代碼,無論是純文本替換還是驗證 - 雖然驗證代碼不僅僅檢查名稱是否存在,它也處理符號鏈接,這非常有趣。 (另外請注意,由於給定的字符串都是字符串文字,因此無法在原位可靠地對其進行修改。) –

+0

我的意思是'\\'謝謝您的更正!我想做文本替換,因爲我假設所有這些文件夾都存在。你知道這些微軟API函數可能是什麼嗎? (我假設我不會處理符號鏈接,但處理這些會更好) – Ryan

回答

0

我看了一下我們的源代碼,發現我的評論描述的實際算法相當不準確。因此,我將提供一個工作樣本來代替:

#include <iostream> 
#include <string> 
#include <vector> 

using namespace std; 

void strTok(const string &text, char delim, vector<string> &tokens) 
{ 
    for (size_t i = 0, j, n = text.size(); i < n; i = j) { 
    while (i < n && text[i] == delim) ++i; 
    j = text.find(delim, i); 
    if (j > n) j = n; 
    tokens.push_back(text.substr(i, j - i)); 
    } 
} 

string filePathResolve(string filePath) 
{ 
    // make paths Unix-style 
    for (char &c : filePath) if (c == '\\') c = '/'; 
    // consider UNC paths 
    const char *root = ""; 
    if (filePath.length() >= 2 && filePath.compare(0, 2, "//") == 0) { 
    root = "//"; filePath.erase(0, 2); 
    } 
    // split file path into list 
    vector<string> list; strTok(filePath, '/', list); 
    // remove all non-functional entries (occurrences of '//' and '/.') 
    for (size_t i = list.size(); i--;) { 
    if (list[i].empty() || list[i] == ".") list.erase(list.begin() + i); 
    } 
    for (size_t i = 1; i < list.size(); ++i) { 
    if (list[i] == ".." && list[i - 1] != "..") { 
     list.erase(list.begin() + i - 1, list.begin() + i + 1); 
     i -= 2; 
    } 
    } 
    // rebuilt path from list 
    filePath = root; 
    if (list.size()) { 
    filePath += list.front(); 
    for (size_t i = 1, n = list.size(); i < n; ++i) { 
     (filePath += '/') += list[i]; 
    } 
    } 
    // done 
    return filePath; 
} 

int main() 
{ 
    string samples[] = { 
    "\\folder1\\..\\folder1\\file.dat", 
    "\\folder1\\folder2\\..\\..\\folder1\\file.dat", 
    "\\folder1\\folder3\\..\\folder2\\..\\folder1\\file.dat", 
    "\\.\\folder1\\..\\folder1\\file.dat", 
    "folder1\\..\\folder1\\.\\file.dat" 
    }; 
    for (string path : samples) { 
    cout << "original: " << path << endl 
     << "resolved: " << filePathResolve(path) << endl; 
    } 
    // done 
    return 0; 
} 

測試在VS2013在Windows 10(64位):

original: \folder1\..\folder1\file.dat 
resolved: folder1/file.dat 
original: \folder1\folder2\..\..\folder1\file.dat 
resolved: folder1/file.dat 
original: \folder1\folder3\..\folder2\..\folder1\file.dat 
resolved: folder1/folder1/file.dat 
original: \.\folder1\..\folder1\file.dat 
resolved: folder1/file.dat 
original: folder1\..\folder1\.\file.dat 
resolved: folder1/file.dat 

由於我們的軟件旨在爲便攜式,我們更喜歡/作爲目錄分隔符。然而,這可以很容易地適應於相反的方向,即首先將每個/替換爲\\並且僅使用後者。

恕我直言,最關鍵的部分是UNC paths。對於我們的運氣,我們的客戶似乎更少了解他們。至少,我從來沒有對此抱怨(多年)。

重新閱讀上面鏈接的維基百科文章,我意識到URL也被提及。 該算法無法正確處理URL。

+0

非常感謝你提供這個!如果沒有以前的功能,這就是我想要實現自己的想法。但是,@Retired Ninja指出我'_fullpath()',它將返回一個絕對路徑和我想要的相對路徑,所以我將使用它。 – Ryan

+0

我注意到這也跟着退休忍者的鏈接。這可能是更好的解決方案(讓操作系統去做)。我甚至考慮將我們的軟件中的代碼替換爲我從中得到的樣本。對於一個便攜式解決方案,我想提一提[SO:安全的跨平臺功能來獲得規範化的路徑](https://stackoverflow.com/questions/7129096/safe-cross-platform-function-to-get-normalized -path)也是。 – Scheff