#pragma once #include #include #include #include #include #include "String.StringView.hpp" #ifdef DSTRING_EXPORTS #define DSTRING_API _declspec(dllexport) #else #define DSTRING_API _declspec(dllimport) #endif #ifdef _DSTRING_STATIC_ #undef DSTRING_API #define DSTRING_API #endif #ifndef DSTRING_EXPORTS #ifdef _WIN64 #ifdef _DEBUG #pragma comment (lib, "ECOM.Utility.DString64D.lib") #else #pragma comment (lib, "ECOM.Utility.DString64.lib") #endif #else // X86 #endif #endif // DSTRING_EXPORTS namespace ECOM::Utility::String { class WString; // using size_type = unsigned int; // 用 unsigned int 比较好, 但是会造成很多编译警告 using size_type = int; //----------------------------------------------------------------------------- // DStringData //----------------------------------------------------------------------------- namespace { struct DStringData { long nRefs; // reference count size_type nDataLength; // length of data (including terminator) size_type nAllocLength; // length of allocation // char data[nAllocLength] char * data () // char* to managed data { return (char *) (this + 1); } }; } //----------------------------------------------------------------------------- // DString //----------------------------------------------------------------------------- class DSTRING_API DString { public: using value_type = DString; using reference = value_type &; using const_reference = const value_type &; public: // Constructors DString (); // DString (const char * lpsz); DString (const char * lpsz, int nLength); // DString (const unsigned char * lpsz) { Init(); *this = (const char *) lpsz; } // std::string 支持 std::string (char * p), 即支持隐式从 char * 构造, // 因此这里变成显示的构造, 以避免 DString (const char *) 的默认构造 explicit DString (const std::string & Src); DString (const DString & Src); DString (DString && Src); public: ~DString (); public: // get data length size_type GetLength () const; size_type GetByteLength () const { return GetLength (); } size_type GetAllocLength () const { return GetData ()->nAllocLength; } size_type size () const { return GetLength (); }; public: bool empty () const { return IsEmpty (); } bool IsEmpty () const { return GetLength () <= 0; } void Clear (); void Release (); public: char GetAt (int nIndex) const { // ASSERT(nIndex >= 0); // ASSERT(nIndex < GetData()->nDataLength); return m_pchData [nIndex]; } char operator [] (int nIndex) const { return GetAt (nIndex); } void SetAt (int nIndex, char ch); int Count (char ch) const; int Count (const StringView & Sub) const; public: DString & operator = (const char *) = delete; DString & operator = (const DString & S); DString & operator = (DString && S); DString & operator = (char ch); DString & operator = (const std::string & S) { AssignCopy (static_cast (S.size ()), S.c_str ()); return (*this); } DString & operator = (const StringView & S) { return Assign (S); } DString & operator = (std::initializer_list lst) { return Assign (lst); } DString & operator = (std::initializer_list lst) { return Assign (lst); } public: //< 这些函数被声明为废除, 避免误写误用. 如果不废除, 编译器将认为/转化为 Append (char) // 当然可以设计成自动转换 { return Append (From (v)); } // 但是万一用户真是写错了, 自动转换就变成帮倒忙了 // 2022-12-26 DString & Append (const char * v) = delete; // 改用 "..."_sv 代替 DString & Append (int v) = delete; DString & Append (unsigned int v) = delete; DString & Append (short v) = delete; DString & Append (unsigned short v) = delete; DString & Append (long v) = delete; DString & Append (unsigned long v) = delete; DString & Append (float v) = delete; DString & Append (double v) = delete; //> DString & Append (unsigned char ch) { return Append (static_cast (ch)); } DString & Append (char ch) { ConcatInPlace (1, &ch); return *this; } DString & Append (const DString & S) { ConcatInPlace (S.GetData ()->nDataLength, S.m_pchData); return *this; } DString & Append (const StringView & S); DString & Append (const std::string_view & S); DString & Append (const std::string & S) { ConcatInPlace (static_cast (S.length ()), S.c_str()); return *this; } // DString & operator += (const char * lpsz) = delete; // 改用 "..."_sv 代替 DString & operator += (const DString & S) { return Append (S); } DString & operator += (char ch) { return Append (ch); } DString & operator += (const StringView & S) { return Append (S); } // DString & operator += (const std::string & S) { return Append (S); } DString & operator += (std::initializer_list lst) { return Append (lst); } //< DString & operator << (const char * lpsz) = delete; // 改用 "..."_sv 代替 // 不废除了, 某些强制赋值还是需要的. // 如果不做提前声明, 编译时发生 C2678: 无法找到匹配的运算符 // 2023-11-14 //> DString & operator << (const DString & S) { return Append (S); } DString & operator << (char ch) { return Append (ch); } DString & operator << (const StringView & S) { return Append (S); } DString & operator << (short v) { return Append (From (v)); } DString & operator << (int v) { return Append (From (v)); } DString & operator << (long v) { return Append (From (v)); } DString & operator << (UINT16 v) { return Append (From (v)); } DString & operator << (UINT32 v) { return Append (From (v)); } DString & operator << (unsigned long v) { return Append (From (v)); } // DString & operator << (const std::string & S) { return Append (S); } DString & operator << (std::initializer_list lst) { return Append (lst); } public: int Compare (const char * With) const; int CompareNoCase (const char * With) const; int Compare (const DStringView & With) const; int Compare (const DString & With) const; //< 增加命名空间后, std::map 就需要如下内置比较函数 bool operator == (const DString & with) const { return Compare (with) == 0; } bool operator != (const DString & with) const { return Compare (with) != 0; } bool operator < (const DString & with) const { return Compare (with) < 0; } bool operator > (const DString & with) const { return Compare (with) > 0; } bool operator <= (const DString & with) const { return Compare (with) <= 0; } bool operator >= (const DString & with) const { return Compare (with) >= 0; } //> public: DString Mid (int nFirst, int nCount) const; DString Mid (int nFirst) const; DString Left (int nCount) const; DString Right (int nCount) const; // characters from beginning that are also in passed string DString SpanIncluding (const char * lpszCharSet) const; // characters from beginning that are not also in passed string DString SpanExcluding (const char * lpszCharSet) const; public: void MakeUpper (); void MakeLower (); void MakeReverse (); public: int TrimLeft (); // 返回去除的字符数 int TrimRight (); // 返回去除的字符数 void TrimLeft (char chTarget); void TrimLeft (const StringView & szTargets); void TrimRight (char chTarget); void TrimRight (const StringView & szTargets); DString Trim () const { DString copy = *this; copy.TrimRight (); copy.TrimLeft (); return copy; } public: // 用指定的字符填充左边/右边/中间, 直到总长度达到指定值为止 void JustLeft (int ToLength, char ch = ' '); void JustRight (int ToLength, char ch = ' '); void JustCenter (int ToLength, char ch = ' '); public: int Replace (char chOld, char chNew); int Replace (const DString & Old, const StringView & New); int Replace (const StringView & Old, const StringView & New); int NCReplace (const StringView & Old, const StringView & New); int ReplaceTabs (int abstand); int Remove (const StringView & Sub); int Remove (char chRemove); int RemoveSpace (); int RemovePunctuation (); int RemoveControl (); // 用谓词函数来判断单个字符是否应该删除, 如果返回 true 就删除 int Remove (std::function pred); int NCRemove (const StringView & Sub); int NCRemove (char chRemove); public: int Insert (int nIndex, char ch); int Insert (int nIndex, const StringView & Sub); int Delete (int nIndex, int nCount = 1); void Repeat (char ch, int n); void Repeat (const StringView & S, int n); public: // Pred 返回 true, 表明找到, 否则下一个字符 using tPred = std::function ; public: int Find (char ch, int nStart = 0) const; int Find (tPred && pred, int nStart = 0) const; int Find (const StringView & Sub, int nStart = 0) const; int Find (const DString & Sub, int nStart = 0) const; int ReverseFind (char ch, int nStart = 0) const; int ReverseFind (const StringView & Sub, int nStart = 0) const; bool StartWith (const StringView & Sub, int iStart = 0) const; bool EndWith (const StringView & Sub, int iStart = 0) const; bool StartWith (const DString & Sub, int iStart = 0) const { return StartWith (Sub.To (), iStart); } bool EndWith (const DString & Sub, int iStart = 0) const { return EndWith (Sub.To (), iStart); } bool StartWith (char ch, int iStart = 0) const; bool EndWith (char ch, int iStart = 0) const; int NCFind (char ch) const; int NCFind (const StringView & Sub) const; public: // start 是起始位置 using tvCallback = std::function ; // 如果回调返回 true, 则继续, 否则停止. Index=第几次回调 using tbCallback = std::function ; int Split (char ch , tvCallback && onFound, int start = 0) const; int Split (tPred && pred, tvCallback && onFound, int start = 0) const; int SplitIf (char ch , tbCallback && onFound, int start = 0) const; int SplitIf (tPred && pred, tbCallback && onFound, int start = 0) const; // 分割成列表 auto SplitTo (char ch , int start = 0) const -> std::list ; auto SplitTo (tPred && pred, int start = 0) const -> std::list ; // 分割成数组, 最多 Max 个 auto SplitMax (int Max, char ch , int start = 0) const -> std::vector ; auto SplitMax (int Max, tPred && pred, int start = 0) const -> std::vector ; // 返回指定 Index 的某一个, 如果找不到: 当 Index=0 时返回本串, 否则返回空串 auto SplitOne (int atIndex, char ch , int start = 0) const -> DString; auto SplitOne (int atIndex, tPred && pred, int start = 0) const -> DString; // Cast public: // return pointer to const string operator const char * () const { return m_pchData; } const char * constBuffer () const { return m_pchData; } char * data () const { return m_pchData; } const char * c_str () const { return m_pchData; } operator bool () const = delete; // 用于自动判别类型 public: template bool Is () const { return false; } template <> bool Is () const { return true; } template <> bool Is () const { return false; } public: static DString From (const int i); static DString From (const long i); static DString From (const unsigned int u); static DString From (const unsigned long u); static DString From (const __int64 i); static DString From (const unsigned __int64 u); static DString From (const double d); static DString From (const std::string_view & Src); static DString From (CV_String & Src) { return DString (Src); } static DString From (const DString & Src) { return DString (Src); } // repeat a single character [[nodiscard]] static DString FromRepeat (char ch, int nRepeat); public: // 为了支持部分组件能与 8.0 一致, 加入如下功能 template [[nodiscard]] static inline DString FromFormat (const StringView & szFormat, Args && ... args); template inline void Format (const StringView & szFormat, Args && ... args); // append with the formatted string template void AppendFormat (const StringView & szFormat, Args && ... args); [[nodiscard]] static DString FromErrorCode (DWORD errorCode); // 通过调用 FormtMessage, 把 Win32 错误码转换成字符串 public: // Access to string implementation buffer as "C" character array // get pointer to modifiable buffer at least as long as nMinBufLength char * GetBuffer (int nMinBufLength); // release buffer, setting length to nNewLength (or to first nul if -1) void ReleaseBuffer (int nNewLength = -1); // get pointer to modifiable buffer exactly as long as nNewLength char * GetBufferSetLength (int nNewLength); void Reserve (int nMinBufLength) { GetBuffer (nMinBufLength); } void reserve (int nMinBufLength) { GetBuffer (nMinBufLength); } public: // 转换函数 double Double () const { return atof (m_pchData); } int Int () const { int i = atoi (m_pchData); if (i) return i; return strtol (m_pchData, nullptr, 16); } long Long () const { long l = atol (m_pchData); if (l) return l; return strtol (m_pchData, nullptr, 16); } char Char () const { return m_pchData[0]; } bool Bool () const; __int64 Int64 () const { __int64 i = _atoi64 (m_pchData); if (i) return i; return _strtoi64 (m_pchData, nullptr, 16); } template T To () const = delete; template <> int To () const { return Int (); } template <> double To () const { return Double (); } template <> float To () const { return (float) Double (); } template <> long To () const { return Long (); } template <> bool To () const { return Bool (); } template <> __int64 To () const { return Int64 (); } template <> unsigned int To () const { return Int (); } template <> unsigned __int64 To () const { return Int64 (); } template <> unsigned long To () const { return Long (); } template <> DString To () const { return *this; } template <> std::string To () const { return std::string { m_pchData, static_cast (GetLength ())}; } template <> std::string_view To () const { return std::string_view { m_pchData, static_cast (GetLength ()) }; } public: // 与 StringView 的转换,构造,赋值等 DString (const StringView & Src); //DString (const std::string_view & Src); // 不能定义这个构造函数, 否则, 编译 eSTR::DString Path (szPath) 时, 编译器会发生警告: 重载函数的调用不明确 public: operator StringView () const noexcept; operator std::string_view () const noexcept; // ? 不能定义这个强制转换函数, 否则, 编译 Hash (DString) 时, 编译器会发生警告: 重载函数的调用不明确 public: template <> StringView To () const; template <> const StringView To () const; DString & Assign (const StringView & _Right); DString & Assign (const std::string_view & _Right); DString & Append (std::initializer_list lst); DString & Append (std::initializer_list lst); DString & Append (std::initializer_list lst); DString & Assign (std::initializer_list lst); DString & Assign (std::initializer_list lst); DString & Assign (std::initializer_list lst); // 万一编译器警告: 调用不明确, 就用模板函数显式告诉编译器 template static DString From (std::initializer_list lst) { DString rc; rc.Assign (lst); return rc; } static DString From (std::initializer_list lst) { DString rc; rc.Assign (lst); return rc; } static DString From (std::initializer_list lst) { DString rc; rc.Assign (lst); return rc; } static DString From (std::initializer_list lst) { DString rc; rc.Assign (lst); return rc; } public: // 判断整个字符串是否是某一类字符组成 bool IsDigit () const; bool IsAlNum () const; bool IsAlpha () const; bool IsUpper () const; bool IsLower () const; bool IsSpace () const; // 判断某个字符是否是某一类字符组成 bool IsDigit (int nPos) const; bool IsAlNum (int nPos) const; bool IsAlpha (int nPos) const; bool IsUpper (int nPos) const; bool IsLower (int nPos) const; bool IsSpace (int nPos) const; public: bool ToCharacterSet (unsigned int CodePage); bool FromCharacterSet (unsigned int CodePage); public: // release memory allocated to but unused by string void FreeExtra (); protected: char * m_pchData; // pointer to ref counted string data // implementation helpers DStringData * GetData () const { return ((DStringData *) m_pchData)-1; } bool IsNil () const; // 用来判断 m_pchData 是否等于 DStringPchNil void Init (); void AllocCopy (DString & dest, int nCopyLen, int nCopyIndex, int nExtraLen) const; void AllocBuffer (int nLen); void AssignCopy (int Len, const char * S); void ConcatCopy (int L1, const char * S1, int L2, const char * S2); void ConcatInPlace (int Len, const char * S); void CopyBeforeWrite (); void AllocBeforeWrite (int nLen); DString & Assign (const DString & Src); // 拷贝赋值 void MoveAssign (DString & Src); void MoveAssign (DString && Src); protected: static void Release (DStringData * pData); static void FreeData (DStringData * pData); //----------------------------------------------------------------------------- // Token类用来对字符串进行标识符切分 //----------------------------------------------------------------------------- public: class DSTRING_API Token { public: Token (const DString & str, bool bSkipPunctuation = false) : m_Str (str), m_bSkipPunctuation (bSkipPunctuation) { // 在Restart之前先初始化这个变量,因为Restart之后需要立即调用Next, // 而Next函数需要这个变量 Restart (); } public: operator bool () const { return m_bContinue; }; operator DString () const { return Current (); }; public: // 定位到下一个标识符 bool Next (void); // 定位到下一个标识符,但是以出作为分割符 bool Next (char sep); // 定位到行尾,Current返回直到行尾的所有字符,但是不包括行尾的回车或换行 bool NextLine (void); DString Current (void) const; // 获得当前标识符,或者当前行 bool IsValid () const { return (m_nL <= m_nR); }; void Clear (void) { m_nL = 0; m_nR = -1; m_nNext = 0; m_bContinue = true; m_nStrLength = 0; } void Restart (void) // 重新开始 { m_szDoc = m_Str; Clear (); m_nStrLength = (int) strlen (m_szDoc); Next (); } bool SkipPunctuation (bool bSkipPunctuation) { bool tmp = m_bSkipPunctuation; m_bSkipPunctuation =bSkipPunctuation; return tmp; } void operator ++ () // ++Token; prevfix { Next (); } void operator ++ (int) // Token++; postfix { Next (); } DString operator () (void) const { return Current (); } protected: int FindWhitespace (int nChar) const; // 从nChar开始,定位到下一个非空字符,并返回这个位置的索引,如果找不到,返回-1 int FindChar (int nChar, char ch) const; // 从nChar开始,在字符串中寻找与ch相同的下一个ch,并返回这个位置的索引,如果找不到,返回-1 protected: const DString & m_Str; const char * m_szDoc; int m_nL; // 当前标识符的左边界 int m_nR; // 当前标识符的右边界 int m_nNext; // 下一个标识符的初始位置 bool m_bContinue; // 可用继续迭代吗? int m_nStrLength; // 字符串长度; bool m_bSkipPunctuation; // Next()时跳过标点符号,即Current()不会返回遇到的标点符号 }; }; } namespace eSTR = ECOM::Utility::String; DSTRING_API eSTR::DString operator + (const eSTR::DString & S1, const eSTR::DString & S2); DSTRING_API eSTR::DString operator + (const eSTR::DString & S, char ch); DSTRING_API eSTR::DString operator + (const eSTR::DString & S1, const eSTR::StringView & S2); DSTRING_API eSTR::DString operator + (const eSTR::StringView & S1, const eSTR::DString & S2); DSTRING_API eSTR::DString operator + (const eSTR::StringView & S1, char ch); DSTRING_API eSTR::DString operator + (char ch, const eSTR::DString & S); DSTRING_API eSTR::DString operator + (const eSTR::DString & S1, const std::string_view & S2); DSTRING_API eSTR::DString operator + (const std::string_view & S1, const eSTR::DString & S2); DSTRING_API eSTR::DString operator + (const std::string_view & S1, char ch); DSTRING_API eSTR::DString operator + (const eSTR::DString & S1, const std::string & S2); DSTRING_API eSTR::DString operator + (const std::string & S1, const eSTR::DString & S2); DSTRING_API eSTR::DString operator + (const eSTR::StringView & S1, const eSTR::StringView & S2); // Compare helpers #if 0 // 如下比较重载将导致编译器无法选择, 因此注释掉 DSTRING_API inline bool operator == (const eSTR::DString & s1, const eSTR::DString & s2) { return s1.Compare (s2) == 0; } DSTRING_API inline bool operator != (const eSTR::DString & s1, const eSTR::DString & s2) { return s1.Compare (s2) != 0; } DSTRING_API inline bool operator < (const eSTR::DString & s1, const eSTR::DString & s2) { return s1.Compare (s2) < 0; } DSTRING_API inline bool operator > (const eSTR::DString & s1, const eSTR::DString & s2) { return s1.Compare (s2) > 0; } DSTRING_API inline bool operator <= (const eSTR::DString & s1, const eSTR::DString & s2) { return s1.Compare (s2) <= 0; } DSTRING_API inline bool operator >= (const eSTR::DString & s1, const eSTR::DString & s2) { return s1.Compare (s2) >= 0; } #endif DSTRING_API inline bool operator == (const eSTR::DString & s1, const eSTR::StringView s2) { return s1.Compare (s2) == 0; } DSTRING_API inline bool operator != (const eSTR::DString & s1, const eSTR::StringView s2) { return s1.Compare (s2) != 0; } DSTRING_API inline bool operator < (const eSTR::DString & s1, const eSTR::StringView s2) { return s1.Compare (s2) < 0; } DSTRING_API inline bool operator > (const eSTR::DString & s1, const eSTR::StringView s2) { return s1.Compare (s2) > 0; } DSTRING_API inline bool operator <= (const eSTR::DString & s1, const eSTR::StringView s2) { return s1.Compare (s2) <= 0; } DSTRING_API inline bool operator >= (const eSTR::DString & s1, const eSTR::StringView s2) { return s1.Compare (s2) >= 0; } #if 1 inline bool operator == (const eSTR::DString & s1, const char * s2) = delete; inline bool operator != (const eSTR::DString & s1, const char * s2) = delete; inline bool operator < (const eSTR::DString & s1, const char * s2) = delete; inline bool operator > (const eSTR::DString & s1, const char * s2) = delete; inline bool operator <= (const eSTR::DString & s1, const char * s2) = delete; inline bool operator >= (const eSTR::DString & s1, const char * s2) = delete; #else DSTRING_API inline bool operator == (const eSTR::DString & s1, const char * s2) { return s1.Compare (s2) == 0; } DSTRING_API inline bool operator != (const eSTR::DString & s1, const char * s2) { return s1.Compare (s2) != 0; } DSTRING_API inline bool operator < (const eSTR::DString & s1, const char * s2) { return s1.Compare (s2) < 0; } DSTRING_API inline bool operator > (const eSTR::DString & s1, const char * s2) { return s1.Compare (s2) > 0; } DSTRING_API inline bool operator <= (const eSTR::DString & s1, const char * s2) { return s1.Compare (s2) <= 0; } DSTRING_API inline bool operator >= (const eSTR::DString & s1, const char * s2) { return s1.Compare (s2) >= 0; } #endif DSTRING_API inline bool operator == (const eSTR::StringView & s1, const eSTR::DString & s2) { return s2.Compare (s1) == 0; } DSTRING_API inline bool operator != (const eSTR::StringView & s1, const eSTR::DString & s2) { return s2.Compare (s1) != 0; } DSTRING_API inline bool operator < (const eSTR::StringView & s1, const eSTR::DString & s2) { return s2.Compare (s1) > 0; } DSTRING_API inline bool operator > (const eSTR::StringView & s1, const eSTR::DString & s2) { return s2.Compare (s1) < 0; } DSTRING_API inline bool operator <= (const eSTR::StringView & s1, const eSTR::DString & s2) { return s2.Compare (s1) >= 0; } DSTRING_API inline bool operator >= (const eSTR::StringView & s1, const eSTR::DString & s2) { return s2.Compare (s1) <= 0; } #if 1 inline bool operator == (const char * s1, const eSTR::DString & s2) = delete; inline bool operator != (const char * s1, const eSTR::DString & s2) = delete; inline bool operator < (const char * s1, const eSTR::DString & s2) = delete; inline bool operator > (const char * s1, const eSTR::DString & s2) = delete; inline bool operator <= (const char * s1, const eSTR::DString & s2) = delete; inline bool operator >= (const char * s1, const eSTR::DString & s2) = delete; #else DSTRING_API inline bool operator == (const char * s1, const eSTR::DString & s2) { return s2.Compare (s1) == 0; } DSTRING_API inline bool operator != (const char * s1, const eSTR::DString & s2) { return s2.Compare (s1) != 0; } DSTRING_API inline bool operator < (const char * s1, const eSTR::DString & s2) { return s2.Compare (s1) > 0; } DSTRING_API inline bool operator > (const char * s1, const eSTR::DString & s2) { return s2.Compare (s1) < 0; } DSTRING_API inline bool operator <= (const char * s1, const eSTR::DString & s2) { return s2.Compare (s1) >= 0; } DSTRING_API inline bool operator >= (const char * s1, const eSTR::DString & s2) { return s2.Compare (s1) <= 0; } #endif #include "String.Format.tlh" template inline void eSTR::DString::Format (const StringView & szFormat, Args && ... args) { char * DString_TLSBuffer_Get (); int DString_TLSBuffer_Size (); auto pb = DString_TLSBuffer_Get (); auto sz = DString_TLSBuffer_Size (); if (! pb) { this->Init (); return; } auto len = StringFormat (pb, sz).Format (szFormat, std::forward (args)...); auto pc = GetBufferSetLength (len); memcpy_s (pc, len, pb, len); } template static inline eSTR::DString eSTR::DString::FromFormat (const StringView & szFormat, Args && ... args) { DString rc; rc.Format (szFormat, std::forward (args)...); return std::move (rc); } template inline void eSTR::DString::AppendFormat (const StringView & szFormat, Args && ... args) { DString rc; rc.Format (szFormat, std::forward (args)...); Append (rc); } template <> struct std::hash { size_t operator() (const char * pc) const noexcept { auto len = strlen (pc); return std::_Hash_array_representation (pc, len); } size_t operator () (const eSTR::DString & from) const noexcept { auto pc = from.constBuffer (); auto len = from.GetLength (); return std::_Hash_array_representation (pc, len); } }; #include "Hash.String.hpp" //< 针对 DString 的 Hash. 目的是避免编译器的错误: 重载函数调用不明确 namespace ECOM::Utility { inline constexpr size_t Hash (const String::DString & SV) { return (Hash (SV.To ())); } }