Строковый токенизатор с несколькими разделителями, включая разделитель без Boost
Мне нужно создать синтаксический анализатор строк на С++. Я попытался использовать
vector<string> Tokenize(const string& strInput, const string& strDelims)
{
vector<string> vS;
string strOne = strInput;
string delimiters = strDelims;
int startpos = 0;
int pos = strOne.find_first_of(delimiters, startpos);
while (string::npos != pos || string::npos != startpos)
{
if(strOne.substr(startpos, pos - startpos) != "")
vS.push_back(strOne.substr(startpos, pos - startpos));
// if delimiter is a new line (\n) then add new line
if(strOne.substr(pos, 1) == "\n")
vS.push_back("\\n");
// else if the delimiter is not a space
else if (strOne.substr(pos, 1) != " ")
vS.push_back(strOne.substr(pos, 1));
if( string::npos == strOne.find_first_not_of(delimiters, pos) )
startpos = strOne.find_first_not_of(delimiters, pos);
else
startpos = pos + 1;
pos = strOne.find_first_of(delimiters, startpos);
}
return vS;
}
Это работает для 2X + 7cos (3Y)
(tokenizer("2X+7cos(3Y)","+-/^() \t");
)
Но дает ошибку времени выполнения для 2X
Мне нужно решение без Boost.
Я попробовал использовать токен-код String Toolkit (StrTk) С++
std::vector<std::string> results;
strtk::split(delimiter, source,
strtk::range_to_type_back_inserter(results),
strtk::tokenize_options::include_all_delimiters);
return results;
но он не дает токена в виде отдельной строки.
например: если я даю ввод как 2X + 3Y
выходной вектор содержит
2X +
3Y
Ответы
Ответ 1
Условие выхода из цикла прерывается:
while (string::npos != pos || string::npos != startpos)
Разрешает ввод с, например pos = npos и startpos = 1.
So
strOne.substr(startpos, pos - startpos)
strOne.substr(1, npos - 1)
end не npos, поэтому substr не останавливается там, где он должен, и BOOM!
Если pos = npos и startpos = 0,
strOne.substr(startpos, pos - startpos)
живет, но
strOne.substr(pos, 1) == "\n"
strOne.substr(npos, 1) == "\n"
умирает. Таким образом,
strOne.substr(pos, 1) != " "
К сожалению, у меня нет времени и я не могу решить это прямо сейчас, но QuestionC получил правильную идею. Лучшая фильтрация. Что-то вроде:
if (string::npos != pos)
{
if (strOne.substr(pos, 1) == "\n") // can possibly simplify this with strOne[pos] == '\n'
vS.push_back("\\n");
// else if the delimiter is not a space
else if (strOne[pos] != ' ')
vS.push_back(strOne.substr(pos, 1));
}
Ответ 2
Что, вероятно, происходит, это сбой при передаче npos
:
lastPos = str.find_first_not_of(delimiters, pos);
Просто добавьте перерывы в свой цикл вместо того, чтобы полагаться на предложение while, чтобы вырваться из него.
if (pos == string::npos)
break;
lastPos = str.find_first_not_of(delimiters, pos);
if (lastPos == string::npos)
break;
pos = str.find_first_of(delimiters, lastPos);
Ответ 3
Я создал небольшую функцию, которая разбивает строку на подстроки (которые хранятся в векторе), и позволяет вам указать, какие символы вы хотите рассматривать как пробельные символы. Обычные пробелы по-прежнему будут рассматриваться как пробельные символы, поэтому вам не нужно это определять. Фактически, все, что он делает, превращает символ, который вы определили как пробел, в фактическое пробельное пространство (пробел char ''). Затем он запускает это в потоке (stringstream), чтобы отделить подстроки и сохранить их в векторе. Возможно, это не то, что вам нужно для этой конкретной проблемы, но, возможно, это может дать вам некоторые идеи.
// split a string into its whitespace-separated substrings and store
// each substring in a vector<string>. Whitespace can be defined in argument
// w as a string (e.g. ".;,?-'")
vector<string> split(const string& s, const string& w)
{
string temp{ s };
// go through each char in temp (or s)
for (char& ch : temp) {
// check if any characters in temp (s) are whitespace defined in w
for (char white : w) {
if (ch == white)
ch = ' '; // if so, replace them with a space char (' ')
}
}
vector<string> substrings;
stringstream ss{ temp };
for (string buffer; ss >> buffer;) {
substrings.push_back(buffer);
}
return substrings;
}
Ответ 4
Было бы здорово, если бы вы могли поделиться некоторой информацией о своей среде. Ваша программа прошла нормально с входным значением 2X на моей Fedora 20 с помощью g++.