#pragma once #include #include #include namespace l0km { template , typename AL = std::allocator > inline std::basic_string toupper (const std::basic_string &src) { std::basic_string dst = src; static const std::locale loc; const std::ctype &ctype = std::use_facet > (loc); for (typename std::basic_string ::size_type i = 0; i < src.size (); ++ i) { dst [i] = ctype.toupper (src [i]); } return dst; } template , typename AL = std::allocator > inline std::basic_string tolower (const std::basic_string &src) { std::basic_string dst = src; static const std::locale loc; const std::ctype &ctype = std::use_facet > (loc); for (typename std::basic_string ::size_type i = 0; i < src.size (); ++ i) { dst [i] = ctype.tolower (src [i]); } return dst; } inline char toupper (char ch) { if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).toupper (ch); } inline char tolower (char ch) { if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).tolower (ch); } inline wchar_t toupper (wchar_t ch) { if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).toupper (ch); } inline wchar_t tolower (wchar_t ch) { if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).tolower (ch); } inline int toupper (int ch) { if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).toupper (ch); } inline int tolower (int ch) { if (ch < -1) return ch; static const std::locale loc; return std::use_facet > (loc).tolower (ch); } } template bool is_blank (ct &ch) { return ch == ct (' ') || ch == ct ('\t') || ch == ct ('\n'); } template , typename AL = std::allocator > std::basic_string NormalizeString (const std::basic_string &str, bool upper = false, bool includemidblank = false) { typedef std::basic_string string_type; string_type result; if (str.empty ()) return result; auto begin_it = str.begin (); auto end_it = str.end (); while (begin_it != end_it && is_blank (*begin_it)) ++begin_it; while (end_it != begin_it && is_blank (*(end_it - 1))) --end_it; bool in_space = false; for (auto it = begin_it; it != end_it; ++ it) { if (is_blank (*it)) { if (includemidblank) { if (!in_space) { result.push_back (E (' ')); in_space = true; } } else { result.push_back (*it); in_space = true; } } else { result.push_back (*it); in_space = false; } } if (upper) return l0km::toupper (result); else return l0km::tolower (result); } template , typename AL = std::allocator > bool IsNormalizeStringEquals (const std::basic_string &l, const std::basic_string &r, bool includemidblank = false) { auto _local_strlen = [] (const E *p) -> size_t { size_t cnt = 0; while (*(p + cnt)) { cnt ++; } return cnt; }; const E *pl = l.c_str (); const E *pr = r.c_str (); while (*pl && is_blank (*pl)) ++ pl; while (*pr && is_blank (*pr)) ++ pr; const E *el = l.c_str () + _local_strlen (l.c_str ()); const E *er = r.c_str () + _local_strlen (r.c_str ()); while (el > pl && is_blank (*(el - 1))) --el; while (er > pr && is_blank (*(er - 1))) --er; while (pl < el && pr < er) { if (includemidblank) { if (is_blank (*pl) && is_blank (*pr)) { while (pl < el && is_blank (*pl)) ++pl; while (pr < er && is_blank (*pr)) ++pr; continue; } else if (is_blank (*pl)) { while (pl < el && is_blank (*pl)) ++pl; continue; } else if (is_blank (*pr)) { while (pr < er && is_blank (*pr)) ++pr; continue; } } if (l0km::tolower (*pl) != l0km::tolower (*pr)) return false; ++ pl; ++ pr; } while (pl < el && is_blank (*pl)) ++ pl; while (pr < er && is_blank (*pr)) ++ pr; return pl == el && pr == er; } template , typename AL = std::allocator > int64_t NormalizeStringCompare (const std::basic_string &l, const std::basic_string &r, bool includemidblank = false) { auto _local_strlen = [] (const E *p) -> size_t { size_t cnt = 0; while (*(p + cnt)) { cnt ++; } return cnt; }; const E *pl = l.c_str (); const E *pr = r.c_str (); while (*pl && is_blank (*pl)) ++ pl; while (*pr && is_blank (*pr)) ++ pr; const E *el = l.c_str () + _local_strlen (l.c_str ()); const E *er = r.c_str () + _local_strlen (r.c_str ()); while (el > pl && is_blank (*(el - 1))) -- el; while (er > pr && is_blank (*(er - 1))) -- er; while (pl < el && pr < er) { if (includemidblank) { if (is_blank (*pl) && is_blank (*pr)) { while (pl < el && is_blank (*pl)) ++pl; while (pr < er && is_blank (*pr)) ++pr; continue; } else if (is_blank (*pl)) { while (pl < el && is_blank (*pl)) ++pl; continue; } else if (is_blank (*pr)) { while (pr < er && is_blank (*pr)) ++pr; continue; } } E chl = l0km::tolower (*pl); E chr = l0km::tolower (*pr); if (chl != chr) return (int64_t)chl - (int64_t)chr; ++ pl; ++ pr; } while (pl < el && is_blank (*pl)) ++ pl; while (pr < er && is_blank (*pr)) ++ pr; if (pl == el && pr == er) return 0; if (pl == el) return -1; if (pr == er) return 1; return (int64_t)l0km::tolower (*pl) - (int64_t)l0km::tolower (*pr); } template bool IsNormalizeStringEquals (const CharT *l, const CharT *r, bool includemidblank = false) { if (!l || !r) return l == r; auto skip_blank = [] (const CharT *&p) { while (*p && is_blank (*p)) ++ p; }; const CharT *p1 = l; const CharT *p2 = r; skip_blank (p1); skip_blank (p2); while (*p1 && *p2) { CharT ch1 = l0km::tolower (*p1); CharT ch2 = l0km::tolower (*p2); if (ch1 != ch2) return false; ++ p1; ++ p2; if (includemidblank) { if (is_blank (*p1) || is_blank (*p2)) { skip_blank (p1); skip_blank (p2); } } } skip_blank (p1); skip_blank (p2); return *p1 == 0 && *p2 == 0; } template int64_t NormalizeStringCompare (const CharT *l, const CharT *r, bool includemidblank = false) { if (!l || !r) return l ? 1 : (r ? -1 : 0); auto skip_blank = [] (const CharT *&p) { while (*p && is_blank (*p)) ++ p; }; const CharT *p1 = l; const CharT *p2 = r; skip_blank (p1); skip_blank (p2); while (*p1 && *p2) { CharT ch1 = l0km::tolower (*p1); CharT ch2 = l0km::tolower (*p2); if (ch1 != ch2) return (ch1 < ch2) ? -1 : 1; ++ p1; ++ p2; if (includemidblank) { if (is_blank (*p1) || is_blank (*p2)) { skip_blank (p1); skip_blank (p2); } } } skip_blank (p1); skip_blank (p2); if (*p1 == 0 && *p2 == 0) return 0; if (*p1 == 0) return -1; return 1; } template , typename AL = std::allocator > bool IsNormalizeStringEmpty (const std::basic_string &str) { return IsNormalizeStringEquals (str, std::basic_string ()); } template , typename AL = std::allocator > std::basic_string StringTrim (const std::basic_string &str, bool includemidblank = false) { typedef std::basic_string string_type; typedef typename string_type::size_type size_type; if (str.empty ()) return string_type (); size_type first = 0; size_type last = str.size (); while (first < last && is_blank (str [first])) ++first; while (last > first && is_blank (str [last - 1])) --last; if (first == last) return string_type (); string_type result; result.reserve (last - first); bool in_space = false; for (size_type i = first; i < last; ++ i) { if (is_blank (str [i])) { if (includemidblank) { if (!in_space) { result.push_back (E (' ')); in_space = true; } } else { result.push_back (str [i]); in_space = true; } } else { result.push_back (str [i]); in_space = false; } } return result; } template , typename AL = std::allocator > size_t GetNormalizeStringLength (const std::basic_string &str, bool includemidblank = false) { typedef typename std::basic_string ::size_type size_type; if (str.empty ()) return 0; size_type first = 0, last = str.size (); while (first < last && is_blank (str [first])) ++first; while (last > first && is_blank (str [last - 1])) --last; if (first == last) return 0; size_t length = 0; bool in_space = false; for (size_type i = first; i < last; ++i) { if (is_blank (str [i])) { if (includemidblank) { if (!in_space) { ++ length; in_space = true; } } else { ++ length; in_space = true; } } else { ++ length; in_space = false; } } return length; } namespace std { template , typename al = std::allocator > class basic_nstring: public std::basic_string { bool default_upper = false, default_include_blank_in_str = false; public: using base = std::basic_string ; using derive = std::basic_nstring ; using typename base::size_type; using typename base::value_type; using base::base; basic_nstring (): base (), default_upper (false), default_include_blank_in_str (false) {} basic_nstring (const ct *pStr): base (pStr), default_upper (false), default_include_blank_in_str (false) {} basic_nstring (const base &str): base (str) {} basic_nstring (base &&str): base (std::move (str)) {} basic_nstring (const ct *data, size_type count): base (data, count), default_upper (false), default_include_blank_in_str (false) {} template basic_nstring (const ct (&arr) [N]) : base (arr, N) {} template basic_nstring (InputIt first, InputIt last): base (first, last), default_upper (false), default_include_blank_in_str (false) {} bool upper_default () const { return this->default_upper; } bool upper_default (bool value) { return this->default_upper = value; } bool include_blank_in_str_middle () const { return this->default_include_blank_in_str; } bool include_blank_in_str_middle (bool value) { return this->default_include_blank_in_str = value; } base normalize (bool upper, bool includemidblank) const { return NormalizeString (*this, upper, includemidblank); } base normalize (bool upper) const { return this->normalize (upper, default_include_blank_in_str); } base normalize () const { return this->normalize (default_upper); } base upper (bool includemidblank) const { return NormalizeString (*this, true, includemidblank); } base upper () const { return this->upper (default_include_blank_in_str); } base lower (bool includemidblank) const { return NormalizeString (*this, false, includemidblank); } base lower () const { return this->lower (default_include_blank_in_str); } base trim (bool includemidblank) const { return StringTrim (*this, includemidblank); } base trim () const { return this->trim (default_include_blank_in_str); } size_t length (bool includemidblank) const { return GetNormalizeStringLength (*this, includemidblank); } size_t length () const { return length (default_include_blank_in_str); } bool empty () const { return IsNormalizeStringEmpty (*this); } bool equals (const base &another, bool includemidblank) const { return IsNormalizeStringEquals (*this, another, includemidblank); } bool equals (const base &another) const { return equals (another, default_include_blank_in_str); } int64_t compare (const base &another, bool includemidblank) const { return NormalizeStringCompare (*this, another, includemidblank); } int64_t compare (const base &another) const { return compare (another, default_include_blank_in_str); } base &string () { return *this; } base to_string (bool upper, bool includemidblank) const { return this->normalize (upper, includemidblank); } base to_string (bool upper) const { return this->normalize (upper, default_include_blank_in_str); } base to_string () const { return this->normalize (default_upper); } bool operator == (const base &other) const { return equals (other, false); } bool operator != (const base &other) const { return !equals (other, false); } bool operator < (const base &other) const { return compare (other, false) < 0; } bool operator > (const base &other) const { return compare (other, false) > 0; } bool operator <= (const base &other) const { return compare (other, false) <= 0; } bool operator >= (const base &other) const { return compare (other, false) >= 0; } int64_t operator - (const base &other) const { return compare (other, false); } template , typename AL = std::allocator > static bool equals (const std::basic_string &l, const std::basic_string &r, bool remove_mid_blank = false) { return IsNormalizeStringEquals (l, r, remove_mid_blank); } template , typename AL = std::allocator > static int64_t compare (const std::basic_string &l, const std::basic_string &r, bool remove_mid_blank = false) { return NormalizeStringCompare (l, r, remove_mid_blank); } template , typename AL = std::allocator > static std::basic_string normalize (const std::basic_string &str, bool to_upper = false, bool remove_mid_blank = false) { return NormalizeString (str, to_upper, remove_mid_blank); } template , typename AL = std::allocator > static std::basic_string trim (const std::basic_string &str, bool remove_mid_blank = false) { return StringTrim (str, remove_mid_blank); } template , typename AL = std::allocator > static size_t length (const std::basic_string &str, bool remove_mid_blank = false) { return GetNormalizeStringLength (str, remove_mid_blank); } template , typename AL = std::allocator > static bool empty (const std::basic_string &str) { return IsNormalizeStringEmpty (str); } template , typename AL = std::allocator > static std::basic_nstring to_nstring (std::basic_string &str) { return std::basic_nstring (str); } template , typename AL = std::allocator > static std::basic_nstring toupper (const std::basic_nstring &str) { return l0km::toupper (str); } template , typename AL = std::allocator > static std::basic_nstring tolower (const std::basic_nstring &str) { return l0km::tolower (str); } }; typedef basic_nstring nstring; typedef basic_nstring wnstring; }