/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2020 Pelican Mapping * http://osgearth.org * * osgEarth is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ #ifndef OSGEARTH_STRING_UTILS_H #define OSGEARTH_STRING_UTILS_H 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace osgEarth { namespace Util { extern OSGEARTH_EXPORT const std::string EMPTY_STRING; using StringVector = std::vector; using StringSet = std::set; using StringTable = std::unordered_map; /** Replaces all the instances of "pattern" with "replacement" in "in_out" */ extern OSGEARTH_EXPORT std::string& replaceIn( std::string& in_out, const std::string& pattern, const std::string& replacement ); /** Replaces all the instances of "pattern" with "replacement" in "in_out" (case-insensitive) */ extern OSGEARTH_EXPORT std::string& ciReplaceIn( std::string& in_out, const std::string& pattern, const std::string& replacement ); /** * Trims whitespace from the ends of a string. */ extern OSGEARTH_EXPORT std::string trim( const std::string& in ); /** * Trims whitespace from the ends of a string; in-place modification on the string to reduce string copies. */ extern OSGEARTH_EXPORT void trim2( std::string& str ); //! Removes leading and trailing whitespace, and replaces all other //! whitespace with single spaces extern OSGEARTH_EXPORT std::string trimAndCompress(const std::string& in); /** * True is "ref" starts with "pattern" */ extern OSGEARTH_EXPORT bool startsWith( const std::string& ref, const std::string& pattern, bool caseSensitive =true, const std::locale& locale =std::locale() ); /** * True is "ref" ends with "pattern" */ extern OSGEARTH_EXPORT bool endsWith( const std::string& ref, const std::string& pattern, bool caseSensitive =true, const std::locale& locale =std::locale() ); /** * Case-insensitive compare */ extern OSGEARTH_EXPORT bool ciEquals( const std::string& lhs, const std::string& rhs, const std::locale& local = std::locale() ); /** * Case-insensitive STL comparator */ inline bool ci_char_equals(char c1, char c2) { return std::tolower(c1) == std::tolower(c2); } inline bool ci_equals(const std::string& lhs, const std::string& rhs) { return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin(), ci_char_equals); } struct ci_string_less { bool operator()(const std::string& lhs, const std::string& rhs) const { for(size_t i=0; i std::tolower(rhs[i])) return false; } return lhs.size() < rhs.size(); } }; extern OSGEARTH_EXPORT std::string joinStrings( const StringVector& input, char delim ); /** Returns a lower-case version of the input string. */ extern OSGEARTH_EXPORT std::string toLower( const std::string& input ); /** Parses a color string in the form "255 255 255 255" (r g b a [0..255]) into an OSG color. */ extern OSGEARTH_EXPORT osg::Vec4ub stringToColor(const std::string& str, osg::Vec4ub default_value); /** Creates a string in the form "255 255 255 255" (r g b a [0..255]) from a color */ extern OSGEARTH_EXPORT std::string colorToString( const osg::Vec4ub& c ); /** Converts a string to a vec3f */ extern OSGEARTH_EXPORT osg::Vec3f stringToVec3f( const std::string& str, const osg::Vec3f& default_value ); /** Converts a vec3f to a string */ extern OSGEARTH_EXPORT std::string vec3fToString( const osg::Vec3f& v ); /** Parses an HTML color ("#rrggbb" or "#rrggbbaa") into an OSG color. */ extern OSGEARTH_EXPORT osg::Vec4f htmlColorToVec4f( const std::string& html ); /** Makes an HTML color ("#rrggbb" or "#rrggbbaa") from an OSG color. */ extern OSGEARTH_EXPORT std::string vec4fToHtmlColor( const osg::Vec4f& c ); /** Makes a valid filename out of a string */ extern OSGEARTH_EXPORT std::string toLegalFileName( const std::string& input, bool allowSubdir=false, const char* replacementChar=NULL); /** Generates a hashed integer for a string (poor man's MD5) */ extern OSGEARTH_EXPORT unsigned hashString( const std::string& input ); /** Same as hashString but returns a string value. */ extern OSGEARTH_EXPORT std::string hashToString(const std::string& input); /** * Gets the total number of seconds formatted as H:M:S */ extern OSGEARTH_EXPORT std::string prettyPrintTime( double seconds ); /** * Gets a pretty printed version of the given size in MB. */ extern OSGEARTH_EXPORT std::string prettyPrintSize( double mb ); //! Extract the "i-th" token from a delimited string extern OSGEARTH_EXPORT std::string getToken(const std::string& input, unsigned i, const std::string& delims=","); //------------------------------------------------------------------------ // conversion templates // converts a string to primitive using serialization template inline T as( const std::string& str, const T& default_value ) { T temp = default_value; std::istringstream strin( str ); if ( !strin.eof() ) strin >> temp; return temp; } // template specialization for integers (to handle hex) #define AS_INT_DEC_OR_HEX(TYPE) \ template<> inline TYPE \ as< TYPE >(const std::string& str, const TYPE & dv) { \ TYPE temp = dv; \ std::istringstream strin( trim(str) ); \ if ( !strin.eof() ) { \ if ( str.length() >= 2 && str[0] == '0' && str[1] == 'x' ) { \ strin.seekg( 2 ); \ strin >> std::hex >> temp; \ } \ else { \ strin >> temp; \ } \ } \ return temp; \ } AS_INT_DEC_OR_HEX(int) AS_INT_DEC_OR_HEX(unsigned) AS_INT_DEC_OR_HEX(short) AS_INT_DEC_OR_HEX(unsigned short) AS_INT_DEC_OR_HEX(long) AS_INT_DEC_OR_HEX(unsigned long) // template specialization for a bool template<> inline bool as( const std::string& str, const bool& default_value ) { std::string temp = toLower(str); return temp == "true" || temp == "yes" || temp == "on" ? true : temp == "false" || temp == "no" || temp == "off" ? false : default_value; } template<> inline osg::Vec3f as( const std::string& str, const osg::Vec3f& default_value ) { return stringToVec3f(str, default_value); } // template specialization for string template<> inline std::string as( const std::string& str, const std::string& default_value ) { return str; } // snips a substring and parses it. template inline bool as(const std::string& in, unsigned start, unsigned len, T default_value) { std::string buf; std::copy( in.begin()+start, in.begin()+start+len, std::back_inserter(buf) ); return as(buf, default_value); } // converts a primitive to a string template inline std::string toString(const T& value) { std::stringstream out; //out << std::setprecision(20) << std::fixed << value; out << std::setprecision(20) << value; std::string outStr; outStr = out.str(); return outStr; } // template speciallization for a bool to print out "true" or "false" template<> inline std::string toString(const bool& value) { return value ? "true" : "false"; } template<> inline std::string toString(const osg::Vec3f& value) { return vec3fToString(value); } /** * Assembles and returns an inline string using a stream-like << operator. * Example: * std::string str = Stringify() << "Hello, world " << variable; */ struct Stringify { operator std::string () const { std::string result; result = buf.str(); return result; } template Stringify& operator << (const T& val) { buf << val; return (*this); } Stringify& operator << (const Stringify& val) { buf << (std::string)val; return (*this); } protected: std::stringstream buf; }; template<> inline Stringify& Stringify::operator << (const bool& val) { buf << (val ? "true" : "false"); return (*this); } template<> inline Stringify& Stringify::operator << (const osg::Vec3f& val) { buf << val.x() << " " << val.y() << " " << val.z(); return (*this); } template<> inline Stringify& Stringify::operator << (const osg::Vec3d& val ) { buf << val.x() << " " << val.y() << " " << val.z(); return (*this); } template<> inline Stringify& Stringify::operator << (const osg::Vec4f& val) { buf << val.r() << " " << val.g() << " " << val.b() << " " << val.a(); return (*this); } /** * Splits a string up into a vector of strings based on a set of * delimiters, quotes, and rules. */ class OSGEARTH_EXPORT StringTokenizer { public: StringTokenizer( const std::string& delims =" \t\r\n", const std::string& quotes ="'\"" ); StringTokenizer( const std::string& input, StringVector& output, const std::string& delims =" \t\r\n", const std::string& quotes ="'\"", bool keepEmpties =true, bool trimTokens =true); StringTokenizer( const std::string& input, StringTable& output, const std::string& delims = " \t\r\n", const std::string& keypairseparators = "=", const std::string& quotes = "'\"", bool keepEmpties = true, bool trimTokens = true); void tokenize( const std::string& input, StringVector& output ) const; bool& keepEmpties() { return _allowEmpties; } bool& trimTokens() { return _trimTokens; } void addDelim( char delim, bool keepAsToken =false ); void addDelims( const std::string& delims, bool keepAsTokens =false ); void addQuote( char delim, bool keepInToken =false ); void addQuotes( const std::string& delims, bool keepInTokens =false ); private: using TokenMap = std::map; TokenMap _delims; TokenMap _quotes; bool _allowEmpties; bool _trimTokens; }; } } namespace osgEarth { namespace Strings = osgEarth::Util; } #endif // OSGEARTH_STRING_UTILS_H