盡管這項任務可能很受歡迎,但我很驚訝竟然沒有這個問題。是否可以在不撰寫自己的決議器的情況下做到這一點?必須跳過一行中的兩個或多個空格。如果沒有,這是我的解決方案
vector<string> split_with_backslash(const string &s)
{
vector<string> ret;
const char *ps = s.c_str();
while (*ps ) {
std::stringstream ss;
switch (*ps) {
default:
ss << *ps;
break;
case ' ': case '\t': case '\n':
ret.push_back(ss.str());
ss.str(string());
ss.clear();
break;
case '\\':
if (!(* ps == ' ' || *ps == '\t' || *ps == '\n'))
--ps;
break;
}
}
return ret;
}
我不擅長 cpp 迭代器,所以我用過 c_str()
編輯:wordexp為@MarekR添加示例。它與問題有關,因為wordexp很好地處理了引號/退格符,而不是下面的特殊符號。
在這里,我正在準備要執行的管道。這樣我擺脫了'|' 標志,它wordexp不吃,但仍然有<>&(&為了簡單起見,我不考慮。
vector<string> subcommands;
boost::split(subcommands, cpp_buf, boost::is_any_of("|"));
wordexp_t res;
switch (wordexp(subcommands.back().c_str(), &res, 0)) {
case 0:
break;
case WRDE_NOSPACE:
wordfree(&res);
default:
exit(EXIT_FAILURE);
}
uj5u.com熱心網友回復:
你提供的代碼非常接近你想要它做的事情;只需要一個細微的變化:將std::stringstream ss;宣告移動到回圈之前(即之外)while。stringstream就目前而言,在該回圈的每次迭代中都會創建一個新的(空)物件。
但是,有一種(可能)更簡單的方法來實作相同的目標,通過使用“轉義標志”來表示任何空格前面都帶有反斜杠,并且只有在該標志為 false 時才將您的子字串推送到結果向量:
vector<string> split_with_backslash(const string& s)
{
vector<string> ret;
bool escape = false;
std::stringstream ss{};
for (auto ps : s) { // "ps" is now a simple "char" but I've kept the name
switch (ps) {
default:
ss << ps;
escape = false;
break;
case ' ': case '\t': case '\n':
if (!escape) {
ret.push_back(ss.str());
ss.str(string());
ss.clear();
}
else {
ss << ps; // If you want the escaped space to be included in the string
escape = false;
}
break;
case '\\':
escape = true;
break;
// The following alternative "case '\\'" block will allow input of
// escaped backslash characters (if that's required) ...
/* case '\\':
if (escape) {
ss << ps;
escape = false;
}
else {
escape = true;
}
break; */
}
}
if (!ss.str().empty()) ret.push_back(ss.str()); // Don't forget final sub-string!
return ret;
}
uj5u.com熱心網友回復:
這是一個可以讓您避免分配(除非您使用split_all)的版本,并且還可以處理轉義的反斜杠,并且包括測驗用例:
#include <string>
#include <vector>
// Needed for C 17 compatibility.
// In C 20, just use the string_view constructor.
template<class It>
std::string_view string_view_from_it(It b, It e)
{
return std::string_view(&*b, e - b);
}
std::string_view skip_space(std::string_view s)
{
auto it = s.begin();
for (; it != s.end(); it)
{
if (!std::isspace(*it))
break;
}
return string_view_from_it(it, s.end());
}
std::pair<std::string_view, std::string_view> split_one(std::string_view s)
{
bool escaped = false;
auto it = s.begin();
for (; it != s.end(); it)
{
if (escaped)
{
escaped = false;
continue;
}
if (*it == '\\')
escaped = true;
else if (std::isspace(*it))
break;
}
return {string_view_from_it(s.begin(), it), string_view_from_it(it, s.end())};
}
std::vector<std::string_view> split_all(std::string_view s)
{
std::vector<std::string_view> v;
s = skip_space(s);
while (!(s = skip_space(s)).empty())
{
auto pair = split_one(s);
v.push_back(pair.first);
s = pair.second;
}
return v;
}
#include <iostream>
int main()
{
for (std::string_view s : {
"",
" ",
" a b ",
"hello\\ world",
" \\ \\\\ \\ \\",
})
{
auto v = split_all(s);
std::cout << "split('" << s << "') = [";
bool first = true;
for (auto s : v)
{
if (!first)
std::cout << ", ";
first = false;
std::cout << "'" << s << "'";
}
std::cout << "]" << std::endl;
}
}
也就是說,此時我更喜歡真正的詞法分析器,并實際處理反斜杠(包括“輸入末尾的反斜杠”)。
我也更喜歡禁止除換行符以外的所有控制字符 - 特別是 CR 和 TAB - 或者至少在早期階段將它們標準化。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/362058.html
上一篇:為BST實作Add方法
