Поскольку вам нужно принять три значения из одного ввода строки, это проблема encoding.
Кодирование иногда выполняется путем введения требований фиксированной ширины для некоторых или всех полей, но здесь это явно не подходит, поскольку нам необходимо поддерживать пути файловой системы переменной ширины и первое значение (которое, как представляется, спецификатора режима) также может быть переменной шириной. Вот и все.
Это оставляет 4 возможных решений для кодирования с переменной шириной:
1: однозначного разделителя.
Если вы можете выбрать символ разделителя, который гарантированно не будет отображаться в разделительных значениях, тогда вы можете разделить его. Например, если NUL не гарантируется и не быть частью значения режима или значения пути, то мы можем сделать это:
std::vector<std::string> v_input = split(input,'\0');
Или, может быть, характер трубы:
std::vector<std::string> v_input = split(input,'|');
Поэтому вход будет должны быть даны как это (для символа трубы):
file_upload|/home/user/Space Dir/file.out|/home/user/Other Dir/blah
2: Escaping.
Вы можете написать код для итерации по строке ввода и правильного разделения его на неэкранированные экземпляры символа разделителя. Исключенные экземпляры не будут рассматриваться как разделители. Вы можете параметризовать escape-символ. Например:
std::vector<std::string> escapedSplit(std::string str, char delimiter, char escaper) {
std::vector<std::string> res;
std::string cur;
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] == delimiter) {
res.push_back(cur);
cur.clear();
} else if (str[i] == escaper) {
++i;
if (i == str.size()) break;
cur.push_back(str[i]);
} else {
cur.push_back(str[i]);
} // end if
} // end for
if (!cur.empty()) res.push_back(cur);
return res;
} // end escapedSplit()
std::vector<std::string> v_input = escapedSplit(input,' ','\\');
С входом как:
file_upload /home/user/Space\ Dir/file.out /home/user/Other\ Dir/blah
3: Цитирование.
Вы можете написать код для итерации по входной строке и правильного разбиения его на некотируемые экземпляры символа разделителя. Цитированные экземпляры не будут рассматриваться как разделители. Вы можете параметризовать символ кавычки.
Усложнение этого подхода состоит в том, что невозможно включить символ кавычки в пределах указанной цитаты, если не ввести механизм экранирования, аналогичный решению № 2. Общая стратегия заключается в том, чтобы позволить повторению символа цитаты избежать этого. Например:
std::vector<std::string> quotedSplit(std::string str, char delimiter, char quoter) {
std::vector<std::string> res;
std::string cur;
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] == delimiter) {
res.push_back(cur);
cur.clear();
} else if (str[i] == quoter) {
++i;
for (; i < str.size(); ++i) {
if (str[i] == quoter) {
if (i+1 == str.size() || str[i+1] != quoter) break;
++i;
cur.push_back(quoter);
} else {
cur.push_back(str[i]);
} // end if
} // end for
} else {
cur.push_back(str[i]);
} // end if
} // end for
if (!cur.empty()) res.push_back(cur);
return res;
} // end quotedSplit()
std::vector<std::string> v_input = quotedSplit(input,' ','"');
С входом как:
file_upload "/home/user/Space Dir/file.out" "/home/user/Other Dir/blah"
или даже просто:
file_upload /home/user/Space" "Dir/file.out /home/user/Other" "Dir/blah
4: Длина стоимости.
Наконец, вы можете написать код, чтобы взять длину перед каждым значением и только захватить много символов. Нам может потребоваться спецификатор длины фиксированной ширины или пропустить разделительный символ после спецификатора длины.Например (примечание: свет на проверку ошибок):
std::vector<std::string> lengthedSplit(std::string str) {
std::vector<std::string> res;
size_t i = 0;
while (i < str.size()) {
size_t len = std::atoi(str.c_str());
if (len == 0) break;
i += (size_t)std::log10(len)+2; // +1 to get base-10 digit count, +1 to skip delim
res.push_back(str.substr(i,len));
i += len;
} // end while
return res;
} // end lengthedSplit()
std::vector<std::string> v_input = lengthedSplit(input);
С вводом в:
11:file_upload29:/home/user/Space Dir/file.out25:/home/user/Other Dir/blah
Как насчет требует, что создатель этих топонимов кавычки вокруг каталогов, которые имеют пробелы? Если они не соответствуют установленным вами правилам, это проблема пользователя, а не ваша. – PaulMcKenzie
Есть ли причина, по которой вы принимаете все 3 параметра через одну строку, считанную с stdin? Вместо этого вы можете прочитать каждый параметр в своей строке stdin или взять каждый параметр из аргументов командной строки в 'argv'. Любой из этих двух подходов мог бы решить проблему пространства. – bgoldst
Как бы вы указали разницу между пространством, которое разделяет параметры и пространство в имени каталога? – Galik