2015-05-10 41 views
13

我想将一个字符串分隔成多个字符串来制作一个自定义的终端。到目前为止,我一直在使用strtok来分离控制信号,但是我不明白如何区分特定的角色实例。例如:在C++中分隔字符串

string input = "false || echo \"hello world\" | grep hello";

当试图函数strtok这个input并尝试使用|分离输出将是:

falseecho "hello world"grep hello

相反,我想输出到成为:

false || echo "hello world"grep hello

我该如何让strtok以不同的方式对待|||而不是说它们是相同的?

+1

“*我怎么能有strtok的治疗?|和||不同,而不是它说他们是一样的*” - 这是因为'strtok'认为每个字符在第二个参数是一个分隔符。而且,它不会返回空字符串。相关[1](http://stackoverflow.com/questions/29847915/implementing-strtok-whose-delimiter-has-more-than-one-character),[2](http://stackoverflow.com/questions/ 7079694/is-there-a-way-split-a-string-on-multiple-characters-in-c?lq = 1) –

回答

8
#include <iostream> 
#include <string> 
#include <algorithm> 
#include <vector> 
using namespace std; 

vector<string> split(string sentence,char delim) 
{ 
    string tempSentence = ""; 
    tempSentence += delim; 
    tempSentence += sentence; 
    tempSentence += delim; 

    string token; 
    vector<string> tokens; 
    for (int i=1;i<tempSentence.length()-1;++i) 
    { 
     if (tempSentence[i] == delim && tempSentence[i-1] != delim && tempSentence[i+1] != delim) 
     { 
      if (token.length()) tokens.push_back(token); 
      token.clear(); 
     } 
     else 
     { 
      token += tempSentence[i]; 
     } 
    } 
    if (token.length()) tokens.push_back(token); 

    return tokens; 
} 

int main() { 
    string sentence = "false || echo \"hello world\" | grep hello"; 
    char delim='|'; 

    vector<string> tokens = split(sentence,delim); 


    for_each(tokens.begin(), tokens.end(), [&](string t) { 
     cout << t << endl; 
    }); 

} 

难看又长!但工作!

+0

问题在用户想要分隔字符串的情况下,如何更改代码使用'||'来替代,因为使用你的代码是行不通的,因为'char delim'只能是一个字符。 也谢谢你,因为如果你正在寻找一个单一的分界,它的工作完美。 – divyanshch

+1

这很容易修复,只需用一个字符串替换即可。但是,使用多个可能的分隔符之一是一个不容易添加的功能。 –

1

strtok()将逐个字符地扫描字符,而不考虑它寻找的前后字符。如果你想更聪明的扫描,你需要自己实施额外的检查。

由于strtok只是返回找到标记的字符串中的位置,您必须手动检查要返回的标记的第一个字符以查看它是否也是“|”,然后相应地执行。

更好的解决方案是查看这里使用正则表达式。这听起来像你想要分裂的符号不仅仅是|,而是|被空间包围 - 也就是说,你实际上是在三个字符符号(空间 - 管道空间)上搜索和分割

1

我想说你的问题的答案首先不是使用strtok(),的问题,甚至在手册页中都有记录(至少在Linux上)。

其次,确保你有测试。使用测试驱动的开发对于这些任务来说是必须的,因为这里有几个简单的事情可能会相互影响,并且在一个地方修复错误会导致另一个错误。此外,还有一些工具(例如各种YACC变体和类似的生成器),允许您指定抽象语法,然后将此定义转换为C++代码。我建议这些用于任何非平凡的任务。最后,如果你只是为了好玩而学习,那么编写一个循环或一组函数来从字符串中提取各种令牌是一种好方法。

1
#include <iostream> 
#include <string> 
#include <algorithm> 

using namespace std; 

int main() { 
    string input = "false || echo \"hello world\" | grep hello"; 

    string::iterator itr; 

    itr = input.begin(); 

    do { 
     itr = search_n(itr, input.end(), 1, '|'); 

     if (itr < input.end() - 1) 
     { 
      if (*(itr + 1) == '|') 
      { 
       itr = itr + 2; 
       continue; 
      } 
     }   

     if (itr < input.end()) 
     { 
       *itr = ','; 
       itr ++; 
     } 

    } while (itr < input.end()); 

    cout << input << endl; 

    return 0; 
} 
1

一个相当简单和直接的解决方案,似乎解决您的问题。

的的std :: string :: find()方法搜索第一次出现由它的参数指定的序列 (在这种情况下,字符串 '分隔符')的字符串。当指定pos时, 搜索仅包含位置pos处或之后的字符。

编辑

#include <iostream> 
    #include <string> 
    int main(int argc, char const *argv[]) 
    { 
     std::string s = "false || echo \"hello world\" | grep hello"; 
     std::string delimiter = "|"; 

     size_t pos = 0, pos1 = 0, flag = 0; 
     std::string token, token1; 
     while ((pos = s.find(delimiter)) != std::string::npos) { 
      pos1 = s.find(delimiter, pos + delimiter.length()); 
      while (pos1 == pos+1){ 
       pos = pos1; 
       pos1 = s.find(delimiter, pos + delimiter.length()); 
       flag = 1; 
      } 
      if (flag) { 
       token = s.substr(0, pos1); 
       std::cout << token << std::endl; 
       if (pos1 > s.length()) 
        exit(0); 
       s.erase(0, pos1 + delimiter.length()); 
      } 
      else{ 
       token = s.substr(0, pos); 
       std::cout << token << std::endl; 
       s.erase(0, pos + delimiter.length()); 
      } 

     } 
     std::cout << s << std::endl; 
     return 0; 
    } 

输出

假||回声的“Hello World”

的grep你好

+0

此代码在 'echo“hello world”的情况下不起作用| grep hello | grep的world' 输出应该预计: '回声的 “Hello World”'' grep的hello' 'grep的world' 而它是: '回声的 “Hello World” | grep hello' 'grep world' – divyanshch

+0

立即试用!这似乎很好。 – mrdoubtful

+0

你可以尝试优化代码,但... – mrdoubtful