給定檔案路徑字串,提取**最內層副檔名**(最後一個 `.` 之後的部分)。需支援:
#include // MFC 核心,含 CString
// 遞迴取得最內層副檔名
CString GetExtName(CString fileName) {
int pos = fileName.Find('.'); // 找第一個 '.'
if (pos == -1) {
return fileName; // 無 '.',整個字串視為「副檔名」(或按需求回傳空)
}
// 找到 '.',遞迴處理其後子串
return GetExtName(fileName.Mid(pos + 1));
}
#include
#include
// 迭代版:更高效、無棧溢位風險
std::string get_extension(std::string_view filename) {
size_t pos = filename.rfind('.'); // 找最後一個 '.'
if (pos == std::string_view::npos || pos == 0) // 無 '.' 或開頭即 '.'
return std::string(filename); // 或回傳空串 ""
return std::string(filename.substr(pos + 1));
}
// 遞迴版(教學用)
std::string get_extension_recursive(std::string_view filename) {
size_t pos = filename.find('.'); // 找第一個 '.'
if (pos == std::string_view::npos)
return std::string(filename);
return get_extension_recursive(filename.substr(pos + 1));
}
關鍵差異:標準庫用 `rfind`(反向查找)一次定位,**遞迴版用 `find` 多次切片**。迭代版 O(n) 單次掃描,遞迴版 O(k·n) 多次掃描(k 為層數)。
int main() {
std::string input;
while (true) {
std::cout << "輸入檔名 (空行結束): ";
if (!std::getline(std::cin, input) || input.empty()) break;
std::string ext = get_extension(input);
if (ext == "txt") std::cout << "輸出: txt\n";
else if (ext == "wmv") std::cout << "輸出: wmv\n";
else if (ext == "exe") std::cout << "輸出: exe\n";
else std::cout << "輸出: " << ext << " (未識別類型)\n";
}
return 0;
}
| 輸入 | 遞迴/迭代輸出 | 說明 |
|---|---|---|
| `11.exe` | `exe` | 單層 |
| `11.exe.wmv` | `wmv` | 雙層,取最內層 |
| `111.exe.wmv.txt` | `txt` | 三層 |
| `README` | `README` | 無點號,全回傳 |
| `.bashrc` | `bashrc` | 隱藏檔,視為無副檔名 |
| `archive.tar.gz` | `gz` | 常見壓縮檔 |
| `file.` | `""` (空串) | 結尾為點,副檔名為空 |
| 維度 | 遞迴版 | 迭代版 (rfind) |
|---|---|---|
| 時間複雜度 | O(k·n) | O(n) |
| 空間複雜度 | O(k) 棧幀 | O(1) |
| 最大層數限制 | 受限於棧大小(通常 >1000 安全) | 無限制 |
| 程式碼簡潔度 | 高(函數式風格) | 中 |
| 生產環境建議 | ❌ 不推薦 | ✅ 推薦 |
// 需求:隱藏檔 .bashrc 視為「無副檔名」,回傳空串
std::string get_ext_strict(std::string_view fn) {
size_t pos = fn.rfind('.');
if (pos == std::string_view::npos || pos == 0 || pos == fn.size() - 1)
return ""; // 無點、點在開頭、點在結尾
return std::string(fn.substr(pos + 1));
}
檔案副檔名解析是字串處理的基礎題。**遞迴寫法**展示了「問題分解為子問題」的思維,適合教學;**迭代 `rfind` 寫法**才是工業級標準——單次掃描、常數空間、無棧溢位風險。實際專案中請直接使用 `