C++ 带空格的拆分字符串路径
我正在编写一个程序,该程序应该由用户接收3个参数:文件上传“本地路径”“远程路径” 代码示例:C++ 带空格的拆分字符串路径,c++,C++,我正在编写一个程序,该程序应该由用户接收3个参数:文件上传“本地路径”“远程路径” 代码示例: std::vector split(std::string str, char delimiter) { std::vector<string> v; std::stringstream src(str); std::string buf; while(getline(src, buf, delimiter)) { v.push_back(buf);
std::vector split(std::string str, char delimiter) {
std::vector<string> v;
std::stringstream src(str);
std::string buf;
while(getline(src, buf, delimiter)) {
v.push_back(buf);
}
return v;
}
void function() {
std::string input
getline(std::cin, input);
// user input like this: file_upload /home/Space Dir/file c:\dir\file
std::vector<std::string> v_input = split(input, ' ');
// the code will do something like this
if(v_input[0].compare("file_upload") == 0) {
FILE *file;
file = fopen(v_input[1].c_str(), "rb");
send_upload_dir(v_input[2].c_str());
// bla bla bla
}
}
std::vector split(std::string str,字符分隔符){
std::向量v;
std::stringstream src(str);
std::字符串buf;
while(getline(src、buf、分隔符)){
v、 推回(buf);
}
返回v;
}
空函数(){
字符串输入
getline(标准::cin,输入);
//用户输入如下:file\u upload/home/Space Dir/file c:\Dir\file
标准::向量v_输入=分割(输入');
//代码将执行如下操作
如果(v_输入[0]。比较(“文件上传”)==0{
文件*文件;
file=fopen(v_输入[1].c_str(),“rb”);
发送上传目录(v_input[2].c_str());
//呜呜呜呜
}
}
我的问题是:第二个和第三个参数是目录,那么它们可以在名称中包含空格。如何使分割函数不改变第二个和第三个参数的空格
我想在目录中加上引号,并创建一个函数来识别,但不能100%工作,因为程序还有其他函数,它们只需要2个参数,而不是3个参数。有人能帮忙吗?
编辑:/home/user/Space Dir/file.out几天前,我遇到了类似的问题,解决方法如下: 首先我创建了一个副本,然后用一些填充来替换副本中带引号的字符串以避免空格,最后根据副本中的空格索引分割原始字符串 以下是我的完整解决方案: 您可能还需要删除双引号、修剪原始字符串等:
#include <sstream>
#include<iostream>
#include<vector>
#include<string>
using namespace std;
string padString(size_t len, char pad)
{
ostringstream ostr;
ostr.fill(pad);
ostr.width(len);
ostr<<"";
return ostr.str();
}
void splitArgs(const string& s, vector<string>& result)
{
size_t pos1=0,pos2=0,len;
string res = s;
pos1 = res.find_first_of("\"");
while(pos1 != string::npos && pos2 != string::npos){
pos2 = res.find_first_of("\"",pos1+1);
if(pos2 != string::npos ){
len = pos2-pos1+1;
res.replace(pos1,len,padString(len,'X'));
pos1 = res.find_first_of("\"");
}
}
pos1=res.find_first_not_of(" \t\r\n",0);
while(pos1 < s.length() && pos2 < s.length()){
pos2 = res.find_first_of(" \t\r\n",pos1+1);
if(pos2 == string::npos ){
pos2 = res.length();
}
len = pos2-pos1;
result.push_back(s.substr(pos1,len));
pos1 = res.find_first_not_of(" \t\r\n",pos2+1);
}
}
int main()
{
string s = "234 \"5678 91\" 8989";
vector<string> args;
splitArgs(s,args);
cout<<"original string:"<<s<<endl;
for(size_t i=0;i<args.size();i++)
cout<<"arg "<<i<<": "<<args[i]<<endl;
return 0;
}
前几天我也遇到过类似的问题,解决方法如下: 首先我创建了一个副本,然后用一些填充来替换副本中带引号的字符串以避免空格,最后根据副本中的空格索引分割原始字符串 以下是我的完整解决方案: 您可能还需要删除双引号、修剪原始字符串等:
#include <sstream>
#include<iostream>
#include<vector>
#include<string>
using namespace std;
string padString(size_t len, char pad)
{
ostringstream ostr;
ostr.fill(pad);
ostr.width(len);
ostr<<"";
return ostr.str();
}
void splitArgs(const string& s, vector<string>& result)
{
size_t pos1=0,pos2=0,len;
string res = s;
pos1 = res.find_first_of("\"");
while(pos1 != string::npos && pos2 != string::npos){
pos2 = res.find_first_of("\"",pos1+1);
if(pos2 != string::npos ){
len = pos2-pos1+1;
res.replace(pos1,len,padString(len,'X'));
pos1 = res.find_first_of("\"");
}
}
pos1=res.find_first_not_of(" \t\r\n",0);
while(pos1 < s.length() && pos2 < s.length()){
pos2 = res.find_first_of(" \t\r\n",pos1+1);
if(pos2 == string::npos ){
pos2 = res.length();
}
len = pos2-pos1;
result.push_back(s.substr(pos1,len));
pos1 = res.find_first_not_of(" \t\r\n",pos2+1);
}
}
int main()
{
string s = "234 \"5678 91\" 8989";
vector<string> args;
splitArgs(s,args);
cout<<"original string:"<<s<<endl;
for(size_t i=0;i<args.size();i++)
cout<<"arg "<<i<<": "<<args[i]<<endl;
return 0;
}
由于需要从单个字符串输入中接受三个值,因此这是一个问题 编码有时是通过对某些或所有字段施加固定宽度要求来完成的,但这在这里显然不合适,因为我们需要支持可变宽度的文件系统路径,并且第一个值(似乎是某种模式说明符)也可能是可变宽度。那就完了 这就为可变宽度编码留下了4种可能的解决方案:
1:明确的分隔符 如果您可以选择一个保证永远不会出现在分隔值中的分隔符,则可以对其进行拆分。例如,如果保证NUL永远不会是模式值或路径值的一部分,那么我们可以这样做:
std::vector<std::string> v_input = split(input,'\0');
2:转义 您可以编写代码来迭代输入行,并在分隔符的未scaped实例上正确拆分它。转义实例将不被视为分隔符。可以参数化转义字符。例如:
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,' ','\\');
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,' ','"');
3:引用 您可以编写代码来迭代输入行,并在分隔符的非引号实例上正确拆分它。引用的实例将不被视为分隔符。可以参数化引号字符 这种方法的一个复杂之处是,除非引入转义机制(类似于解决方案#2),否则不可能将引号字符本身包含在引号范围内。一种常见的策略是允许重复引号字符来转义它。例如:
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,' ','\\');
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
4:长度值 最后,您可以编写代码,在每个值之前取一个长度,并且只获取那么多字符。我们可能需要一个固定宽度的长度说明符,或者跳过长度说明符后面的定界字符。例如(注意:错误检查灯亮):
由于需要从单个字符串输入中接受三个值,因此这是一个问题 编码有时是通过对某些或所有字段施加固定宽度要求来完成的,但这在这里显然不合适,因为我们需要支持可变宽度的文件系统路径,并且第一个值(似乎是某种模式说明符)也可能是可变宽度。那就完了 这就为可变宽度编码留下了4种可能的解决方案:
1:明确的分隔符 如果您可以选择一个保证永远不会出现在分隔值中的分隔符,则可以对其进行拆分。例如,如果保证NUL永远不会是模式值或路径值的一部分,那么我们可以这样做:
std::vector<std::string> v_input = split(input,'\0');
2:转义 您可以编写代码来迭代输入行,并在分隔符的未scaped实例上正确拆分它。转义实例将不被视为分隔符。可以参数化转义字符。例如:
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,' ','\\');
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,' ','"');
3:引用 您可以编写代码来迭代输入行,并在分隔符的非引号实例上正确拆分它。引用的实例将不被视为分隔符。可以参数化引号字符 这种方法的一个复杂之处是,除非引入转义机制(类似于解决方案#2),否则不可能将引号字符本身包含在引号范围内。一种常见的策略是允许重复引号字符来转义它。例如:
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,' ','\\');
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
4:长度值 最后,您可以编写代码,在每个值之前取一个长度,并且只获取那么多字符。我们可能需要一个固定宽度的长度说明符,或者跳过长度说明符后面的定界字符。例如(注:灯亮错误ch