Разделение строки в C++
Я пытаюсь разделить строку на несколько строк, чтобы сделать настроенный терминал. До сих пор я разделял управляющие сигналы с помощью strtok, однако я не понимаю, как отделить конкретные экземпляры символа. Например:
string input = "false || echo "hello world" | grep hello";
при попытке strtok это input
и пытается отделить с помощью |
выход будет:
false
, echo "hello world"
, grep hello
вместо этого, я хотел бы вывод должен быть:
false || echo "hello world"
, grep hello
как я могу иметь strtok лечить |
и ||
по-другому, а не то, что он говорит, что они одинаковы?
5 ответов
#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;
});
}
некрасиво и долго! но работает!
strtok () будет сканировать символ за символом, без учета символов до и после того, что он ищет. Если вы хотите более Умное сканирование, вам нужно будет реализовать дополнительную проверку самостоятельно.
поскольку strtok просто возвращает местоположение в строке, где найден токен, вам придется вручную проверить первый символ возвращаемого токена, чтобы увидеть, является ли он также"|", а затем действовать соответственно.
лучшим решением было бы изучить использование регулярного выражения здесь. Похоже, что символ, который вы хотите разделить, - это не просто A|, а скорее a/, окруженный пробелами, т. е. вы фактически ищете и разделяете символ из трех символов (space - pipe - space)
Я бы сказал, что ответ на ваш вопрос, во-первых, не использовать strtok()
, который имеет множество проблем, которые даже задокументированы в manpage (по крайней мере, в Linux).
во-вторых, убедитесь, что у вас есть тесты. Использование тестовой разработки является обязательным для этих задач, потому что здесь несколько простых вещей могут плохо взаимодействовать друг с другом, а исправление ошибки в одном месте может вызвать проблемы в другом.
далее, есть инструменты (например, различные YACC-вариантов и подобные генераторы), которые позволяют определить абстрактный синтаксис, а затем превратить это определение в C++ код. Я бы предложил их для любой нетривиальной задачи.
наконец, если вы делаете это только для удовольствия и обучения, написание цикла или набора функций для извлечения различных токенов из строки-хороший подход.
#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;
}
довольно простое и простое решение, которое, кажется, решает ваш вопрос.
std:: string:: find() выполняет поиск в строке первого вхождения последовательности, заданной ее аргументами (в данном случае строка 'delimiter'). Когда 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;
}
выход :
false / / Эхо "hello world"
grep привет