Mantid
Loading...
Searching...
No Matches
UserStringParser.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
12#include <boost/lexical_cast.hpp>
13
14namespace Mantid::Kernel {
15
21std::vector<std::vector<unsigned int>> UserStringParser::parse(const std::string &userString) {
22 std::vector<std::vector<unsigned int>> numbers;
23 // first separate commas
24 std::vector<std::string> commaseparatedstrings;
25 if (userString.find(',') != std::string::npos) {
26 commaseparatedstrings = separateComma(userString);
27 }
28 if (!commaseparatedstrings.empty()) {
29 std::vector<std::string>::const_iterator citr;
30 for (citr = commaseparatedstrings.begin(); citr != commaseparatedstrings.end(); ++citr) {
31 parse((*citr), numbers);
32 }
33
34 } else {
35 parse(userString, numbers);
36 }
37 return numbers;
38}
39
45void UserStringParser::parse(const std::string &userString, std::vector<std::vector<unsigned int>> &numbers) {
46
47 // look for separators
48 std::string separators("-+:");
49 // if input contains no separator string
50 if (userString.find_first_of(separators) == std::string::npos) {
51 numbers.emplace_back(1, toUInt(userString));
52 } else if (Contains(userString, '-')) {
53 std::vector<unsigned int> value = separateDelimiters(userString, "-:");
54 if (!value.empty()) {
55 numbers.emplace_back(value);
56 }
57 } else if (Contains(userString, '+')) {
58 std::vector<unsigned int> value = separateDelimiters(userString, "+");
59 if (!value.empty()) {
60 numbers.emplace_back(value);
61 }
62 } else if (Contains(userString, ':')) {
63 std::vector<std::vector<unsigned int>> colonseparated = separateColon(userString);
64 std::vector<std::vector<unsigned int>>::const_iterator citr1;
65 for (citr1 = colonseparated.begin(); citr1 != colonseparated.end(); ++citr1) {
66 numbers.emplace_back((*citr1));
67 }
68 }
69}
70
76bool UserStringParser::Contains(const std::string &input, char ch) {
77 std::string::size_type pos = input.find(ch);
78 return (pos != std::string::npos);
79}
80
85std::vector<std::string> UserStringParser::separateComma(const std::string &input) {
88 return tokens.asVector();
89}
90
95std::vector<std::vector<unsigned int>> UserStringParser::separateColon(const std::string &input) {
96 unsigned int startNum = 0;
97 unsigned int endNum = 0;
98 unsigned int step = 1;
99 std::vector<std::vector<unsigned int>> separatedValues;
100 Tokenize(input, ":", startNum, endNum, step);
101 for (unsigned int num = startNum; num <= endNum; num += step) {
102 separatedValues.emplace_back(1, num);
103 }
104
105 return separatedValues;
106}
107
114std::vector<unsigned int> UserStringParser::separateDelimiters(const std::string &input,
115 const std::string &delimiters) {
116 unsigned int startNum = 0;
117 unsigned int endNum = 0;
118 unsigned int step = 1;
119 std::vector<unsigned int> separatedValues;
120 Tokenize(input, delimiters, startNum, endNum, step);
121
122 for (unsigned int num = startNum; num <= endNum; num += step) {
123 separatedValues.emplace_back(num);
124 }
125 return separatedValues;
126}
127
138void UserStringParser::Tokenize(const std::string &input, const std::string &delimiter, unsigned int &start,
139 unsigned int &end, unsigned int &step) {
141 tokenizer tokens(input, delimiter);
142 // validate the separated tokens
143 if (!isValidStepSeparator(input, tokens.asVector())) {
144 throw std::runtime_error("Non supported format found in the input string " + input +
145 " Step string should be preceded by :");
146 }
147 // convert the parsed string to number
148 convertToNumbers(input, tokens.asVector(), start, end, step);
149}
150
157bool UserStringParser::isValidStepSeparator(const std::string &input, const std::vector<std::string> &tokens) {
158 std::string step_separator;
159 if (tokens.size() == 3) {
160 std::string step = tokens[2];
161
162 std::string::size_type index = input.rfind(step);
163 if (index != std::string::npos) {
164 step_separator = input.substr(index - 1, 1);
165 }
166 // step values must be preceded by colon ':'
167 return (step_separator == ":");
168 }
169 return true;
170}
171
179void UserStringParser::convertToNumbers(const std::string &input, const std::vector<std::string> &tokens,
180 unsigned int &start, unsigned int &end, unsigned int &step) {
181 if (tokens.empty()) {
182 return;
183 }
184 try {
185 start = toUInt(tokens.at(0));
186 end = toUInt(tokens.at(1));
187 if (tokens.size() == 3) {
188 step = toUInt(tokens.at(2));
189 }
190 if (end < start) {
191 throw std::runtime_error("Invalid Input String: End number " + tokens.at(1) +
192 " can not be lower than start number" + tokens.at(0));
193 }
194 if (start + step > end) {
195 throw std::runtime_error("Invalid Input String: End number " + tokens.at(1) +
196 " can not be lower than the sum of start number " + tokens.at(0) + " and step number" +
197 tokens.at(2));
198 }
199 } catch (std::runtime_error &e) {
200 throw std::runtime_error(e.what());
201 } catch (std::out_of_range &) {
202 throw std::runtime_error("Error when parsing the input string " + input);
203 }
204}
209unsigned int UserStringParser::toUInt(const std::string &input) {
210 try {
211 return boost::lexical_cast<unsigned int>(input);
212 } catch (boost::bad_lexical_cast &) {
213 throw std::runtime_error("Error when parsing the input string " + input);
214 }
215}
216} // namespace Mantid::Kernel
double value
The value of the point.
Definition: FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
@ TOK_TRIM
remove leading and trailing whitespace from tokens
const TokenVec & asVector()
Returns a vector of tokenized strings.
bool isValidStepSeparator(const std::string &input, const std::vector< std::string > &tokens)
This method checks the separator preceded by the step string is valid colon ':' is valid separator fo...
void Tokenize(const std::string &input, const std::string &delimiter, unsigned int &start, unsigned int &end, unsigned int &step)
This method removes the separator string from the input string and converts the tokens to unisgned in...
std::vector< std::vector< unsigned int > > separateColon(const std::string &input)
separates a given string to vector of vector of numbers using colon as the delimeter
std::vector< std::vector< unsigned int > > parse(const std::string &userString)
parses a given string into a vector of vector of numbers
std::vector< std::string > separateComma(const std::string &)
separate a given string to a vector of comma separated strings
void convertToNumbers(const std::string &input, const std::vector< std::string > &tokens, unsigned int &start, unsigned int &end, unsigned int &step)
converts the parsed tokens to numbers
unsigned int toUInt(const std::string &input)
converts a string to int.
bool Contains(const std::string &input, char ch)
This method checks the input string contains the character ch.
std::vector< unsigned int > separateDelimiters(const std::string &input, const std::string &delimiters)
separate delimiter string from input string and return a vector of numbers created from the separated...