我是字符串來創建一個std::regex(__FILE__)
作爲單元測試的一部分,它檢查打印文件名的一些異常輸出。std :: regex轉義文件路徑中的反斜槓
在Windows它失敗:
regex_error(error_escape):表達式包含無效轉義字符,或一個尾隨逃逸。
因爲__FILE__
宏擴展包含未轉義的反斜槓。
是否有逃避反斜槓,而不是通過生成的字符串循環更優雅的方式(即用std
算法或一些std::string
功能)?
我是字符串來創建一個std::regex(__FILE__)
作爲單元測試的一部分,它檢查打印文件名的一些異常輸出。std :: regex轉義文件路徑中的反斜槓
在Windows它失敗:
regex_error(error_escape):表達式包含無效轉義字符,或一個尾隨逃逸。
因爲__FILE__
宏擴展包含未轉義的反斜槓。
是否有逃避反斜槓,而不是通過生成的字符串循環更優雅的方式(即用std
算法或一些std::string
功能)?
文件路徑可以包含許多在正則表達式模式中具有特殊含義的字符。在一般情況下僅僅反轉反斜槓是不夠的。
即使是一個簡單的路徑,如C:\Program Files (x86)\Vendor\Product\app.exe
,也包含幾個特殊字符。如果要將其轉換爲正則表達式(或正則表達式的一部分),則不僅需要轉義反斜槓,而且還需要轉義圓括號和句點(點)。
std::string EscapeForRegularExpression(const std::string &s) {
static const std::regex metacharacters(R"([\.\^\$\-\+\(\)\[\]\{\}\|\?\*)");
return std::regex_replace(s, metacharacters, "\\$&");
}
(文件路徑不能包含*
或?
,但我將他們保持功能一般)
幸運的是,我們可以有更多的正則表達式解決我們的正則表達式的問題
如果不通過「無生循環」方針遵守,一個可能更快實現將避免正則表達式:
std::string EscapeForRegularExpression(const std::string &s) {
static const char metacharacters[] = R"(\.^$-+()[]{}|?*)";
std::string out;
out.reserve(s.size());
for (auto ch : s) {
if (std::strchr(metacharacters, ch))
out.push_back('\\');
out.push_back(ch);
}
return out;
}
儘管循環增加了一些混亂,但這種方法允許我們在metacharacters
的定義上下降一定程度的轉義,這是對regex版本的可讀性的勝利。
沒有「原始循環」?我很高興我們沒有一個風格指南... –
@Nicolas Holthaus:Adobe的肖恩家長提出在這個視頻中的「沒有原始循環」的想法:https://channel9.msdn.com/Events/GoingNative/ 2013/CPP-調味 –
最後,我切換到@AdrianMcCarthy的more robust approach。
下面是我在其中得到解決的情況下,有人在此跌倒的問題不雅方法實際上是尋找一個解決辦法:
std::string escapeBackslashes(const std::string& s)
{
std::string out;
for (auto c : s)
{
out += c;
if (c == '\\')
out += c;
}
return out;
}
然後
std::regex(escapeBackslashes(__FILE__));
這是O(N)
這可能是就像你在這裏可以做到的一樣好,但涉及很多字符串複製,我想這並不是絕對必要的。
所有這一切都是逃避反斜槓,這不足以將Windows文件路徑轉換爲有效的正則表達式模式。它不會對其他正則表達式元字符進行任何操作,這些字符可以在路徑名中,例如圓括號。 –
@AdrianMcCarthy當然,但這就是它打算做的。它意味着一個單元測試,而不是一個通用的「正則表達式」製造商,並解決了我需要的唯一一個問題。 –
這裏是polymapper
。
它需要一個操作來獲取元素並返回一個範圍,即「地圖操作」。
它產生一個函數對象,它接受一個容器,並將「映射操作」應用於每個元素。它返回與容器相同的類型,其中每個元素都被「地圖操作」展開/收縮。
template<class Op>
auto polymapper(Op&& op) {
return [op=std::forward<Op>(op)](auto&& r) {
using std::begin;
using R=std::decay_t<decltype(r)>;
using iterator = decltype(begin(r));
using T = typename std::iterator_traits<iterator>::value_type;
std::vector<T> data;
for (auto&& e:decltype(r)(r)) {
for (auto&& out:op(e)) {
data.push_back(out);
}
}
return R{ data.begin(), data.end() };
};
}
這裏是escape_stuff
:
auto escape_stuff = polymapper([](char c)->std::vector<char> {
if (c != '\\') return {c};
else return {c,c};
});
int main() {
std::cout << escape_stuff(std::string(__FILE__)) << "\n";
}
這種方法的優點是,容器的膽量混亂的行爲被分解出來。你編寫的代碼與字符或元素混淆,整體邏輯不是你的問題。
缺點是polymapper有點奇怪,並且不必要的內存分配也完成了。 (那些可以優化出來,但這使得代碼更復雜)。
'__FILE__'應該只打印文件名。你需要完整的路徑嗎? – Hayt
@Hayt _「'__FILE__'應該只打印文件名。」_不一定 –
是的,如果他不需要他們,他可以看看這裏:https://msdn.microsoft.com/en-us/library/027c4t2s .aspx假設問題不是缺少的引號,你已經回答了。並假設他使用MSVC編譯器 – Hayt