Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-13 10:32:10

0001 // -*- C++ -*-
0002 //
0003 // This file is part of YODA -- Yet more Objects for Data Analysis
0004 // Copyright (C) 2008-2025 The YODA collaboration (see AUTHORS for details)
0005 //
0006 #ifndef YODA_STRINGUTILS_H
0007 #define YODA_STRINGUTILS_H
0008 
0009 #include <algorithm>
0010 #include <cstdlib>
0011 #include <limits>
0012 #include <sstream>
0013 #include <stdexcept>
0014 #include <vector>
0015 
0016 namespace YODA {
0017   namespace Utils {
0018 
0019 
0020     /// Exception to be thrown by lexical_cast below
0021     struct bad_lexical_cast : public std::runtime_error {
0022       bad_lexical_cast(const std::string& what) : std::runtime_error(what) {}
0023     };
0024 
0025     /// Convert between any types via stringstream
0026     template<typename T, typename U>
0027     T lexical_cast(const U& in) {
0028       try {
0029         std::stringstream ss;
0030         ss << in;
0031         T out;
0032         ss >> out;
0033         return out;
0034       } catch (const std::exception& e) {
0035         throw bad_lexical_cast(e.what());
0036       }
0037     }
0038 
0039 
0040     /// Generic convenient conversion to string
0041     template <typename T>
0042     inline std::string toStr(const T& x) {
0043       // std::ostringstream ss; ss << x;
0044       // return ss.str();
0045       return lexical_cast<std::string>(x);
0046     }
0047 
0048 
0049     /// Convert a string to a double, accounting for out-of-range errors
0050     inline double toDbl(const std::string& s) {
0051       try {
0052         return std::stod(s);
0053       }
0054       catch (...) {
0055         return std::numeric_limits<double>::quiet_NaN();
0056       }
0057     }
0058 
0059 
0060     /// Convert a string to lower-case
0061     inline std::string toLower(const std::string& s) {
0062       std::string out = s;
0063       std::transform(out.begin(), out.end(), out.begin(), (int(*)(int)) tolower);
0064       return out;
0065     }
0066 
0067 
0068     /// Convert a string to upper-case
0069     inline std::string toUpper(const std::string& s) {
0070       std::string out = s;
0071       std::transform(out.begin(), out.end(), out.begin(), (int(*)(int)) toupper);
0072       return out;
0073     }
0074 
0075 
0076     /// Replace XML reserved characters with &XXXX; encodings
0077     inline std::string encodeForXML(const std::string& in) {
0078       std::string out = in;
0079       typedef std::pair<std::string, std::string> CharsToEntities;
0080       std::vector<CharsToEntities> cs2es;
0081       cs2es.push_back(std::make_pair("&", "&amp;"));
0082       cs2es.push_back(std::make_pair("<", "&lt;"));
0083       cs2es.push_back(std::make_pair(">", "&gt;"));
0084       for (std::vector<CharsToEntities>::const_iterator c2e = cs2es.begin(); c2e != cs2es.end(); ++c2e) {
0085         std::string::size_type pos = -1;
0086         while ( ( pos = out.find(c2e->first, pos + 1) ) != std::string::npos ) {
0087           out.replace(pos, 1, c2e->second);
0088         }
0089       }
0090       return out;
0091     }
0092 
0093 
0094     /// Does the string @a s contain the given substring?
0095     inline bool contains(const std::string& s, const std::string& sub) {
0096       return s.find(sub) != std::string::npos;
0097     }
0098 
0099     /// Does the string @a s start with the given substring?
0100     inline bool startswith(const std::string& s, const std::string& sub) {
0101       return s.find(sub) == 0;
0102     }
0103 
0104     /// Does the string @a s end with the given substring?
0105     inline bool endswith(const std::string& s, const std::string& sub) {
0106       const size_t pos = s.find(sub);
0107       return pos != std::string::npos && pos == (s.size()-sub.size());
0108     }
0109 
0110 
0111     /// In-place trim from start
0112     inline std::string& iltrim(std::string& s) {
0113       s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char c){ return !std::isspace(c); }));
0114 
0115       return s;
0116     }
0117 
0118     /// In-place trim from end
0119     inline std::string& irtrim(std::string& s) {
0120       s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char c){ return !std::isspace(c); }).base(), s.end());
0121       return s;
0122     }
0123 
0124     /// In-place trim from both ends
0125     inline std::string& itrim(std::string& s) {
0126       return iltrim(irtrim(s));
0127     }
0128 
0129 
0130     /// Trim from start
0131     inline std::string ltrim(const std::string& s) { //< @note Could just pass by value, but const& sends a symbolic message
0132       std::string s2 = s;
0133       return iltrim(s2);
0134     }
0135 
0136     /// Trim from end
0137     inline std::string rtrim(const std::string& s) { //< @note Could just pass by value, but const& sends a symbolic message
0138       std::string s2 = s;
0139       return irtrim(s2);
0140     }
0141 
0142     /// Trim from both ends
0143     inline std::string trim(const std::string& s) { //< @note Could just pass by value, but const& sends a symbolic message
0144       std::string s2 = s;
0145       return itrim(s2);
0146     }
0147 
0148     /// @brief Split a string on a specified separator string
0149     inline std::vector<std::string> split(const std::string& s, const std::string& sep) {
0150       std::vector<std::string> dirs;
0151       std::string tmp = s;
0152       while (true) {
0153         const size_t delim_pos = tmp.find(sep);
0154         if (delim_pos == std::string::npos) break;
0155         const std::string dir = tmp.substr(0, delim_pos);
0156         if (dir.length()) dirs.push_back(dir); // Don't insert "empties"
0157         tmp.replace(0, delim_pos+1, "");
0158       }
0159       if (tmp.length()) dirs.push_back(tmp); // Don't forget the trailing component!
0160       return dirs;
0161     }
0162 
0163     /// Split a path string with colon delimiters
0164     ///
0165     /// Ignores zero-length substrings. Designed for getting elements of filesystem paths, naturally.
0166     inline std::vector<std::string> pathsplit(const std::string& path) {
0167       return split(path, ":");
0168     }
0169 
0170     // Annoyingly, this doesn't work without significant SFINAE etc., due to clashes with existing string & stream operators
0171     // /// string + any appending operator for convenience in the YODA namespace
0172     // template <typename T>
0173     // std::string& operator + (std::string& s, const T& x) {
0174     //   s += Utils::toStr(x);
0175     //   return s;
0176     // }
0177     // template <typename T>
0178     // std::string operator + (const T& x, std::string& s) {
0179     //   return Utils::toStr(x) + s;
0180     // }
0181     // template <typename T>
0182     // std::string operator + (const char* s, const T& x) {
0183     //   return s + Utils::toStr(x);
0184     // }
0185     // template <typename T>
0186     // std::string operator + (const T& x, const char* s) {
0187     //   return Utils::toStr(x) + x;
0188     // }
0189 
0190 
0191     /// @brief Get a parameter from a named environment variable, with automatic type conversion
0192     ///
0193     /// @note Return @a fallback if the variable is not defined, otherwise convert its string to the template type
0194     template <typename T>
0195     T getEnvParam(const std::string& name, const T& fallback) {
0196       char* env = getenv(name.c_str());
0197       return env ? lexical_cast<T>(env) : fallback;
0198     }
0199 
0200   }
0201 
0202 }
0203 
0204 #endif