Page MenuHomec4science

string_algorithms.cpp
No OneTemporary

File Metadata

Created
Thu, Nov 7, 07:00

string_algorithms.cpp

/* =============================================================================
Copyright (c) 2014 - 2016
F. Georget <fabieng@princeton.edu> Princeton University
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
============================================================================= */
#include "string_algorithms.hpp"
#include <algorithm>
#define RANGE_SEP ':'
namespace specmicp {
namespace utils {
//! \brief Split a string
std::vector<std::string> split(const std::string& to_split, char separator)
{
std::vector<std::string> splitted;
auto nb_elem = std::count(to_split.begin(), to_split.end(), separator);
splitted.reserve(nb_elem+1);
auto start = to_split.begin();
for (auto current=to_split.cbegin(); current!= to_split.cend(); ++current)
{
if (*current == separator) {
splitted.emplace_back(to_split.substr(
start - to_split.cbegin(), current-start));
start = current + 1;
}
}
// last value
if (start < to_split.cend()) {
splitted.emplace_back(to_split.substr(start - to_split.cbegin()));
}
return splitted;
}
std::string strip(const std::string& to_trim)
{
auto start = to_trim.begin();
auto end = to_trim.end();
// at the beginning
auto current=to_trim.begin();
for (; current!=to_trim.cend(); ++current) {
if (*current != ' ')
{
start = current;
break;
}
}
if (current == to_trim.cend()) {return "";} // empty string
// at the end
for (auto current=to_trim.cend()-1;current>=to_trim.begin(); --current) {
if (*current != ' ')
{
end = ++current;
break;
}
}
return to_trim.substr(start - to_trim.begin(), end-start);
}
void parse_one_term(std::vector<index_t>& numbers, const std::string& term);
void parse_one_term(std::vector<uindex_t>& numbers, const std::string& term);
template <typename T>
std::vector<T> range_indices_impl(const std::string& range_str)
{
std::vector<T> numbers;
const uindex_t nb_sep = std::count(range_str.cbegin(), range_str.cend(), ',');
numbers.reserve(nb_sep+1);
if (nb_sep == 0) { // if only one term
parse_one_term(numbers, range_str);
}
else {
const std::vector<std::string> terms = split(range_str, ',');
for (const auto& term: terms) {
parse_one_term(numbers, term);
}
}
// sort the indices
std::sort(numbers.begin(), numbers.end());
return numbers;
}
template <>
std::vector<index_t> range_indices(const std::string& range_str)
{
return range_indices_impl<index_t>(range_str);
}
template <>
std::vector<uindex_t> range_indices(const std::string& range_str)
{
return range_indices_impl<uindex_t>(range_str);
}
void parse_one_term(std::vector<index_t>& numbers, const std::string &term)
{
if (term == "") return; // check for empty terms
const auto to_anal = strip(term);
const auto is_range = std::find(to_anal.cbegin(), to_anal.cend(), RANGE_SEP);
if (is_range == to_anal.cend()) {
// if just a number
numbers.push_back(std::stol(to_anal));
}
else {
// if a range
const std::string first_str = to_anal.substr(0, is_range-to_anal.cbegin());
const std::string last_str = to_anal.substr(is_range-to_anal.cbegin()+1);
const index_t first = std::stol(first_str);
const index_t last = std::stol(last_str);
for (auto ind=first; ind<=last; ++ind) {
numbers.push_back(ind);
}
}
}
void parse_one_term(std::vector<uindex_t>& numbers, const std::string &term)
{
if (term == "") return; // check for empty terms
const auto to_anal = strip(term);
const auto is_range = std::find(to_anal.cbegin(), to_anal.cend(), RANGE_SEP);
if (is_range == to_anal.cend()) {
// if just a number
auto val = std::stol(to_anal);
if (val < 0) {
throw std::invalid_argument("Negative argurment found in "
"positive ranges : '"+std::to_string(val)
+ "'.");
}
numbers.push_back(val);
}
else {
// if a range
const std::string first_str = to_anal.substr(0, is_range-to_anal.cbegin());
const std::string last_str = to_anal.substr(is_range-to_anal.cbegin()+1);
const index_t first = std::stol(first_str);
if (first < 0 ) {
throw std::invalid_argument("Negative argurment found in "
"positive ranges : '"+std::to_string(first)
+ "'.");
}
const index_t last = std::stol(last_str);
for (auto ind=first; ind<=last; ++ind) {
numbers.push_back(ind);
}
}
}
template <typename T>
class ExpressionParser
{
public:
ExpressionParser(
const std::string& expr,
const std::unordered_map<std::string, T>& vars
):
complete_expr(expr),
variables(vars)
{
}
T parse() {return parse_term(complete_expr);}
T parse_value(const std::string& value);
T parse_factor(const std::string& factor);
T parse_term(const std::string& term);
private:
const std::string& complete_expr;
const std::unordered_map<std::string, T>& variables;
};
template <>
scalar_t ExpressionParser<scalar_t>::parse_value(const std::string& expr)
{
auto trimmed_expr = strip(expr);
if (trimmed_expr == "") {
throw std::invalid_argument("Error while parsing : " + complete_expr);
}
scalar_t val = std::nan("");
try {
std::size_t pos;
val = std::stod(trimmed_expr, &pos);
if (pos != trimmed_expr.size()) {
throw std::logic_error("Error while processing '" + expr +
"'. Just a number was expected."
"Error occured while processing '"
+ complete_expr + "'.");
}
}
catch (const std::invalid_argument& e) {
auto it = variables.find(trimmed_expr);
if (it == variables.cend()) {
throw std::out_of_range("Unknown variable '"+
trimmed_expr + "' in parsing of '"
+ complete_expr +"'.");
}
val = it->second;
}
return val;
}
template <>
index_t ExpressionParser<index_t>::parse_value(const std::string& expr)
{
auto trimmed_expr = strip(expr);
index_t val = INT_MAX;
try {
std::size_t pos;
val = std::stol(trimmed_expr, &pos);
if (pos != trimmed_expr.size()) {
throw std::logic_error("Error while processing" + expr +
". Just a number was expected."
"Error occured while processing "
+ complete_expr + ".");
}
}
catch (const std::invalid_argument& e) {
auto it = variables.find(trimmed_expr);
if (it == variables.cend()) {
throw std::out_of_range("Unknown variable '"+
trimmed_expr + "' in parsing of '"
+ complete_expr +"'.");
}
val = it->second;
}
return val;
}
template <typename T>
T ExpressionParser<T>::parse_factor(const std::string& expr)
{
auto it = expr.find_last_of("*/");
if (it == expr.npos) {
return parse_value(expr);
}
auto val1 = parse_factor(expr.substr(0, it));
auto val2 = parse_value(expr.substr(it+1));
if (expr[it] == '*') {
return val1*val2;
} else {
return val1/val2;
}
return 0;
}
template <typename T>
T ExpressionParser<T>::parse_term(const std::string& expr)
{
auto it = expr.find_first_of("+-");
if (it == expr.npos) {
return parse_factor(expr);
}
else if (it != 0) {
auto val1 = parse_factor(expr.substr(0, it));
auto val2 = parse_factor(expr.substr(it+1));
if (expr[it] == '+') {
return val1+val2;
} else {
return val1-val2;
}
}
else {
if (expr[it] == '-') {
return -parse_term(expr.substr(1));
} else {
return parse_term(expr.substr(1));
}
}
return 0;
}
template <>
scalar_t ExpressionParser<scalar_t>::parse_term(const std::string& expr)
{
auto pred = [](const char& t) -> bool {return ((t == '+') or( t == '-'));};
std::size_t pos = 0;
char op;
auto it = expr.begin();
while (pos < expr.size())
{
it = std::find_if(it, expr.end(), pred);
if (it == expr.cend()) {
pos = expr.size();
break;
}
op = *it;
pos = it-expr.cbegin();
// xe-y notation => it's a number !
if (op == '-' and expr[pos-1] == 'e' and std::isdigit(expr[pos-2]))
{
++it; // jump to next char
continue;
}
else
{
break;
}
}
if (pos == expr.size()) {
return parse_factor(expr);
}
if (pos > 0) {
auto val1 = parse_factor(expr.substr(0, pos));
auto val2 = parse_factor(expr.substr(pos+1));
if (op == '+') {
return val1+val2;
} else {
return val1-val2;
}
}
else {
if (op == '-') {
return -parse_term(expr.substr(1));
} else {
return parse_term(expr.substr(1));
}
}
return 0;
}
template <>
scalar_t parse_expression(
const std::string& expr,
const std::unordered_map<std::string, scalar_t>& variables
)
{
return ExpressionParser<scalar_t>(expr, variables).parse();
}
template <>
index_t parse_expression(
const std::string& expr,
const std::unordered_map<std::string, index_t>& variables
)
{
return ExpressionParser<index_t>(expr, variables).parse();
}
bool string_to_bool(const std::string& to_bool_str)
{
// Contain the strings that matches true or false
static const char* true_str_test[] = {"True", "true", "1", "yes", "Yes", "Y"};
static const char* false_str_test[] = {"False", "false", "0", "no", "No", "N"};
auto trimmed = strip(to_bool_str);
bool val = false;
// test for true
for (auto test: true_str_test) {
if (test == trimmed) {
val = true;
goto exit;
}
}
// test for false
for (auto test: false_str_test) {
if (test == trimmed) {
val = false;
goto exit;
}
}
// no match => error
throw std::invalid_argument("Unrecognized value when converting to bool '"
+ trimmed + "'. Recognized value : true/false."
);
exit:
return val;
}
} //end namespace utils
} //end namespace specmicp

Event Timeline