my functions.h
1. 考虑重叠的 memcpy
void* MemoryCopy(void *dest, const void *src, size_t size) { assert(dest != NULL); assert(src != NULL); if (src == dest) return dest; char *d; const char *s; if ((src > dest) || (src <= (char*)dest - size)) { d = (char*)dest; s = (const char*)src; while (size--) *d++ = *s++; } else /* overlap 重叠情况从高位到低位复制 */ { d = (char*)dest + size - 1; s = (const char*)src + size - 1; while (size--) *d-- = *s--; } return dest; }
2. 字符串分割
(详细参见:https://www.cnblogs.com/htj10/p/11354618.html)
// delim分隔符,所有delim中包含的字符都是分隔符,保留空字符串"",前向分割 void split(const char* str, const char* delim, std::vector<std::string> &vRet) { if (NULL == str || NULL == delim || '\0' == *str || '\0' == *delim) return; const char* p = str; const char* q = NULL; while (*p && (q = strpbrk(p, delim))) { vRet.push_back(std::string(p, q)); ++q; p = q; } if (*p) vRet.push_back(std::string(p)); } // str是待分割的字符串 delim整体作为一个分隔符,保留空字符串"",前向分割 void split2(const char* str, const char* delim, std::vector<std::string> &vRet) { if (NULL == str || NULL == delim || '\0' == *str || '\0' == *delim) return; const int n = strlen(delim); const char* p = str; const char* q = NULL; while (*p && (q = strstr(p, delim))) { vRet.push_back(std::string(p, q)); q = q + n; p = q; } if (*p) vRet.push_back(std::string(p)); } /////////////////////////////////////////// //分割后保留空字符串。sbcssdfs 以s分割得 "" "bc" "" "df" "" void split(const string& str, const string& pattern, vector<string>& ret) { if (pattern.empty()) return; size_t start = 0; size_t index = str.find_first_of(pattern, 0); while (index != string::npos) { ret.push_back(str.substr(start, index - start)); start = index + 1; index = str.find_first_of(pattern, start); } ret.push_back(str.substr(start)); } //pattern作为一个整体当分割符,(不去掉 "") void split(const string& str, const string& pattern, vector<string>& ret) { if (pattern.empty()) return ; size_t start = 0; size_t index = str.find(pattern, 0); while (index != string::npos) { ret.push_back(str.substr(start, index - start)); start = index + pattern.size(); index = str.find(pattern, start); } ret.push_back(str.substr(start)); }
--------
//--------------------------------------------------------------------------------------- // 功能:分割字符串,保留空字符串"",前向分割。(char* 版) // 参数:str 待分割的字符串,delim 分隔符(所有delim中包含的每个字符都是分隔符),vRet 返回分割后的结果 // 例如:"0hello world0.00", " 0" --> "" "hello" "world" "." "" //--------------------------------------------------------------------------------------- void split1(const char* str, const char* delim, std::vector<std::string> &vRet) { if (NULL == str || NULL == delim || '\0' == *str || '\0' == *delim) return; if (NULL == strpbrk(str, delim))//若一个都delim没有查到,就直接返回 return; const int nLen = strlen(str); const char* p = str; const char* q = NULL; while (p < str + nLen) { q = strpbrk(p, delim); if (q != NULL) { vRet.push_back(std::string(p, q)); p = q + 1; } else { vRet.push_back(std::string(p)); break; } } } //--------------------------------------------------------------------------------------- // 功能:分割字符串,保留空字符串"",前向分割。(wchar_t* 版) // 参数:str 待分割的字符串,delim 分隔符(所有delim中包含的每个字符都是分隔符),vRet 返回分割后的结果 // 例如:"0hello world0.00", " 0" --> "" "hello" "world" "." "" //--------------------------------------------------------------------------------------- void split1(const wchar_t* str, const wchar_t* delim, std::vector<std::wstring> &vRet) { if (NULL == str || NULL == delim || '\0' == *str || '\0' == *delim) return; if (NULL == wcspbrk(str, delim))//若一个都delim没有查到,就直接返回 return; const int nLen = wcslen(str); const wchar_t* p = str; const wchar_t* q = NULL; while (p < str + nLen) { q = wcspbrk(p, delim); if (q != NULL) { vRet.push_back(std::wstring(p, q)); p = q + 1; } else { vRet.push_back(std::wstring(p)); break; } } } //--------------------------------------------------------------------------------------- // 功能:分割字符串(整体作为一个分隔符),保留空字符串"",前向分割。(char* 版) // 参数:str是待分割的字符串 delim整体作为一个分隔符,vRet 返回分割后的结果 // 例如:"00hello00world0.00", "00" --> "" "hello" "world0." //--------------------------------------------------------------------------------------- void split2(const char* str, const char* delim, std::vector<std::string> &vRet) { if (NULL == str || NULL == delim || '\0' == *str || '\0' == *delim) return; if (NULL == strstr(str, delim))//若一个都delim没有查到,就直接返回 return; const int nLen = strlen(str); const int n = strlen(delim); const char* p = str; const char* q = NULL; while (p < str + nLen) { q = strstr(p, delim); if (q != NULL) { vRet.push_back(std::string(p, q)); p = q + n; } else { vRet.push_back(std::string(p)); break; } } } //--------------------------------------------------------------------------------------- // 功能:分割字符串(整体作为一个分隔符),保留空字符串"",前向分割。(wchar_t* 版) // 参数:str是待分割的字符串 delim整体作为一个分隔符,vRet 返回分割后的结果 // 例如:"00hello00world0.00", "00" --> "" "hello" "world0." //--------------------------------------------------------------------------------------- void split2(const wchar_t* str, const wchar_t* delim, std::vector<std::wstring> &vRet) { if (NULL == str || NULL == delim || '\0' == *str || '\0' == *delim) return; if (NULL == wcsstr(str, delim))//若一个都delim没有查到,就直接返回 return; const int nLen = wcslen(str); const int n = wcslen(delim); const wchar_t* p = str; const wchar_t* q = NULL; while (p < str + nLen) { q = wcsstr(p, delim); if (q != NULL) { vRet.push_back(std::wstring(p, q)); p = q + n; } else { vRet.push_back(std::wstring(p)); break; } } } //--------------------------------------------------------------------------------------- // 分割字符串str,pattern中的每个字符都是分隔符,前向分割。(std::string 版) // 例如:"0hello world0.00", " 0" --> "" "hello" "world" "." "" //--------------------------------------------------------------------------------------- void split1(const string& str, const string& pattern, vector<string>& ret) { if (pattern.empty() || str.empty()) return; size_t start = 0; size_t index = str.find_first_of(pattern, 0); while (index != string::npos) { ret.push_back(str.substr(start, index - start)); start = index + 1; index = str.find_first_of(pattern, start); } if (start < str.size()) ret.push_back(str.substr(start)); } //--------------------------------------------------------------------------------------- // 分割字符串str,pattern中的每个字符都是分隔符,前向分割。(std::wstring 版) // 例如:"0hello world0.00", " 0" --> "" "hello" "world" "." "" //--------------------------------------------------------------------------------------- void split1(const std::wstring& str, const std::wstring& pattern, vector<std::wstring>& ret) { if (pattern.empty() || str.empty()) return; size_t start = 0; size_t index = str.find_first_of(pattern, 0); while (index != std::wstring::npos) { ret.push_back(str.substr(start, index - start)); start = index + 1; index = str.find_first_of(pattern, start); } if (start < str.size()) ret.push_back(str.substr(start)); } //--------------------------------------------------------------------------------------- // 分割字符串str,pattern整体做为一个分隔符,前向分割。(std::string 版) // 例如:"00hello00world0.00", "00" --> "" "hello" "world0." //--------------------------------------------------------------------------------------- void split2(const string& str, const string& pattern, vector<string>& ret) { if (pattern.empty() || str.empty()) return; size_t nLen = pattern.size(); size_t start = 0; size_t index = str.find(pattern, 0); while (index != string::npos) { ret.push_back(str.substr(start, index - start)); start = index + nLen; index = str.find(pattern, start); } if (start < str.size()) ret.push_back(str.substr(start)); } //--------------------------------------------------------------------------------------- // 分割字符串str,pattern整体做为一个分隔符,前向分割。(std::wstring 版) // 例如:"00hello00world0.00", "00" --> "" "hello" "world0." //--------------------------------------------------------------------------------------- void split2(const std::wstring& str, const std::wstring& pattern, vector<std::wstring>& ret) { if (pattern.empty() || str.empty()) return; size_t nLen = pattern.size(); size_t start = 0; size_t index = str.find(pattern, 0); while (index != std::wstring::npos) { ret.push_back(str.substr(start, index - start)); start = index + nLen; index = str.find(pattern, start); } if (start < str.size()) ret.push_back(str.substr(start)); }
3. 字符串转换(wstring <->string ANSI <-> UTF8)
#include <Windows.h> // std::string ==> std::wstring bool s2ws(const std::string &s,std::wstring &ws) { if (s.empty()) return true; int nLen = ::MultiByteToWideChar(CP_ACP, NULL, s.c_str(), -1, NULL, 0);//-1,返回的nLen包括\0,即s.size()+1 wchar_t *buf = new wchar_t[nLen]; int nWrited = ::MultiByteToWideChar(CP_ACP, NULL, s.c_str(), -1, buf, nLen);//-1: 转换包括\0 ws = buf; delete[] buf; return (nLen == nWrited) ? true : false; } // std::wstring ==> std::string bool ws2s(const std::wstring &ws, std::string &s) { if (ws.empty()) return true; int nLen = ::WideCharToMultiByte(CP_ACP, NULL, ws.c_str(), -1, NULL, 0, NULL, NULL); char* buf = new char[nLen]; int nWrited = ::WideCharToMultiByte(CP_ACP, NULL, ws.c_str(), -1, buf, nLen, NULL, NULL); s = buf; delete[] buf; return (nWrited == nLen) ? true : false; } ///// 转换不同字符集(ANSI:CP_ACP UTF8:CP_UTF8) // ANSI ==> UTF8 bool ANSI_to_UTF8(const std::string &sAnsi, std::string &sUtf8) { if (sAnsi.empty()) return true; std::wstring wsAnsi; int nLen = ::MultiByteToWideChar(CP_ACP, NULL, sAnsi.c_str(), -1, NULL, 0); wchar_t *buf1 = new wchar_t[nLen]; int nWrited = ::MultiByteToWideChar(CP_ACP, NULL, sAnsi.c_str(), -1, buf1, nLen); wsAnsi = buf1; delete[] buf1; if (nWrited != nLen) return false; nLen = ::WideCharToMultiByte(CP_UTF8, NULL, wsAnsi.c_str(), -1, NULL, 0, NULL, NULL); char* buf2 = new char[nLen]; nWrited = ::WideCharToMultiByte(CP_UTF8, NULL, wsAnsi.c_str(), -1, buf2, nLen, NULL, NULL); sUtf8 = buf2; delete[] buf2; return (nWrited == nLen) ? true : false; } // UTF8 ==> ANSI bool UTF8_to_ANSI(const std::string &sUtf8, std::string &sAnsi) { if (sUtf8.empty()) return true; int nLen = ::MultiByteToWideChar(CP_UTF8, NULL, sUtf8.c_str(), -1, NULL, 0); wchar_t *wbuf = new wchar_t[nLen]; int nWrited = ::MultiByteToWideChar(CP_UTF8, NULL, sUtf8.c_str(), -1, wbuf, nLen); std::wstring wsUtf8(wbuf); delete[] wbuf; if (nWrited != nLen) return false; nLen = ::WideCharToMultiByte(CP_ACP, NULL, wsUtf8.c_str(), -1, NULL, 0, NULL, NULL); char* buf = new char[nLen]; nWrited = ::WideCharToMultiByte(CP_ACP, NULL, wsUtf8.c_str(), -1, buf, nLen, NULL, NULL); sAnsi = buf; delete[] buf; return (nWrited == nLen) ? true : false; }
4. 获取exe所在目录
inline CString GetExeDir() { TCHAR buf[512] = { 0 }; ::GetModuleFileName(NULL, buf, 512); CString str(buf); str = str.Left(str.ReverseFind('\\')); return str; }
获取当前dll的路径
char DllPath[MAX_PATH] = { 0 }; GetModuleFileNameA((HINSTANCE)&__ImageBase, DllPath, _countof(DllPath)); // 或者使用 DllMain()中的 hInstance 当前dll句柄 TCHAR szName[MAX_PATH] = { 0 }; GetModuleFileName(hInstance, szName, MAX_PATH);
获取模块句柄的方式
void DumpModule() { HMODULE hModule = GetModuleHandle(NULL);//获取exe的句柄 _tprintf(TEXT("With GetModuleHandle(NULL)=0x%x\r\n"), hModule); _tprintf(TEXT("With _ImageBase=0x%x\r\n"), (HINSTANCE)&__ImageBase);//获取当前句柄(dll或exe) hModule = NULL; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (PCTSTR)DumpModule, &hModule);//获取函数DumpModule所在的模块句柄 _tprintf(TEXT("With GetModuleHandleEx =0x%x\r\n"), hModule); } /* 3个地址是一样的(exe下) With GetModuleHandle(NULL)=0x2b0000 With _ImageBase=0x2b0000 With GetModuleHandleEx =0x2b0000 */ /* 3个地址是不一样的(dll下) With GetModuleHandle(NULL)=0x00c80000 With _ImageBase=0x50360000 With GetModuleHandleEx =0x50360000 */
5. 写日志
#include <io.h> #include <direct.h> #include <time.h> #pragma warning(disable:4996) //写日志Log,nLogMode( 0:LOG_DEBUG, 1:LOG_INFO, 2:LOG_ERROR, 3:LOG_WARNING ) bool WriteLog(const char* szText, const char* szAppName, const char* szSrc, const int nLine, const int nLogMode) { char szFileName[BUFSIZ] = { 0 }; char szBuf[BUFSIZ] = { 0 }; char temp1[32] = { 0 }; char temp2[32] = { 0 }; time_t t = time(0); strftime(temp1, sizeof(temp1), "%Y-%m-%d %H:%M:%S", localtime(&t)); strftime(temp2, sizeof(temp2), "\\%Y%m%d.log", localtime(&t)); ::GetModuleFileNameA(NULL, szBuf, sizeof(szBuf)); strncpy(szFileName, szBuf, strrchr(szBuf, '\\') - szBuf); strcat(szFileName, "\\Log"); if (-1 == _access(szFileName, 0))//文件或文件夹不存在 _mkdir(szFileName);//创建文件夹 strcat(szFileName, temp2); char szLogMode[16] = { 0 }; switch (nLogMode) { case 0:strcpy(szLogMode, "LOG_DEBUG"); break; case 1:strcpy(szLogMode, "LOG_INFO"); break; case 2:strcpy(szLogMode, "LOG_ERROR"); break; case 3:strcpy(szLogMode, "LOG_WARNING"); break; default:strcpy(szLogMode, "LOG_OTHER"); break; } char szTemp[1024] = { 0 }; sprintf(szTemp, "[%s][%s][%s][%s(%d)]\r\n%s\r\n", szAppName, szLogMode, temp1, szSrc, nLine, szText); FILE* fp; if ((fp = fopen(szFileName, "ab")) == NULL) return false; fwrite(szTemp, strlen(szTemp), 1, fp); fclose(fp); return true; }
用法:WriteLog("loveuuuuuuuuu", "PocoLearn", __FILE__, __LINE__, 1);
6. 判断CString是否为数(包括小数)
//判断是否为数(包括小数) bool IsDecimal(const CString& str) { if (str.SpanIncluding(_T(".0123456789")) != str || str[0] == '.' || str.Find(_T("."), str.Find(_T("."))+1) != -1) { //MessageBox(_T("价格不是数字!"), _T("提示")); return false; } return true; }
7. 复制、移动、重命名、删除 文件或文件夹
BOOL CopyFile( LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, BOOL bFailIfExists ); BOOL MoveFile( LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName); BOOL DeleteFile( LPCTSTR lpFileName );//删除文件 BOOL RemoveDirectory(LPCTSTR lpPathName);//删除空文件夹 BOOL CreateDirectory(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); //头文件都在 Winbase.h,注:Windows.h 包含 Winbase.h BOOL b = ::CopyFile(_T("ReadMe.txt"), _T("./test2/123.txt"), FALSE);//FALSE:如果目标位置已经存在同名文件,就覆盖,return 1;//TRUE:如果目标位置已经存在同名文件,就不复制,return 0;//若目标路径不存在,return 0 // CopyFile()不能操作文件夹 // MoveFile()能操作文件夹 //b = ::MoveFile(_T("./123.txt"), _T("./test/123.txt"));//移动文件 //b = ::MoveFile(_T("./123.txt"), _T("./1234.txt"));//重命名文件 //b = ::MoveFile(_T("./123.txt"), _T("./test/234.txt"));//移动文件,并重命名 //b = ::MoveFile(_T("./test"), _T("./res/test"));//移动文件夹 test 到 res夹下 //b = ::MoveFile(_T("./test"), _T("./testt"));//重命名文件夹 b = ::MoveFile(_T("./test"), _T("./res/testt"));//移动文件夹 test 到 res夹下,并重命名文件夹 BOOL b = ::DeleteFile(_T("D:/123.txt"));//删除文件 // 或者 _tremove(_T("D:/test.txt"));// 成功返回0 头文件 <stdio.h> or <io.h> b = ::RemoveDirectory(_T("D:/新建文件夹"));//删除空文件夹,若文件夹里有文件则删除失败。若想删除非空文件夹,要先遍历文件夹内所有文件,删除后再删文件夹。 //或者 _trmdir(_T("D:/新建文件夹")); 也必须是空文件夹,成功返回0 头文件 <direct.h> 或 <tchar.h> b = ::CreateDirectory(_T("D:/testFolder"), NULL);//创建文件夹, //或是 _tmkdir(_T("D:/testFolder")) //调用C运行库函数int mkdir()和int _mkdir() 头文件<direct.h>或 <tchar.h>
复制/移动/删除 时带有系统的进度条提示窗口(参考:https://www.cnblogs.com/ys0103/p/4465888.html)
#include <Windows.h> //复制文件或文件夹 bool CopyFile2(TCHAR *pFrom, TCHAR *pTo) { SHFILEOPSTRUCT FileOp = { 0 }; FileOp.fFlags = FOF_NOCONFIRMATION | //不出现确认对话框 FOF_NOCONFIRMMKDIR; //需要时直接创建一个文件夹,不需用户确定 FileOp.pFrom = pFrom; FileOp.pTo = pTo; FileOp.wFunc = FO_COPY; return SHFileOperation(&FileOp) == 0; } int main() { bool b = CopyFile2(_T("d:\\迅雷下载\\BBC:寻找自我意识_hd.mp4"), _T("e:\\my\\test.mp4"));//注意:只有足够大的文件,才会出现进度条窗口。 CopyFile2(_T("e:\\my"), _T("e:\\my2"));//拷贝文件夹 return 0; } //删除文件或者文件夹 bool DeleteFile2(TCHAR * lpszPath) { SHFILEOPSTRUCT FileOp = { 0 }; FileOp.fFlags = FOF_ALLOWUNDO | //允许放回回收站,若没有该flag就是永久删除 FOF_NOCONFIRMATION; //不出现确认对话框 FileOp.pFrom = lpszPath; FileOp.pTo = NULL; //一定要是NULL FileOp.wFunc = FO_DELETE; //删除操作 return SHFileOperation(&FileOp) == 0; } //移动文件或文件夹 bool MoveFile2(TCHAR *pFrom, TCHAR *pTo) { SHFILEOPSTRUCT FileOp = { 0 }; FileOp.fFlags = FOF_NOCONFIRMATION | //不出现确认对话框 FOF_NOCONFIRMMKDIR; //需要时直接创建一个文件夹,不需用户确定 FileOp.pFrom = pFrom; FileOp.pTo = pTo; FileOp.wFunc = FO_MOVE; return SHFileOperation(&FileOp) == 0; } // 例如:MoveFile2(_T("e:\\my\\test.mp4"), _T("e:\\my2\\")); // MoveFile2(_T("e:\\my2\\test.mp4"), _T("e:\\my\\test2.mp4")); //从命名文件或文件夹 bool ReNameFile(TCHAR *pFrom, TCHAR *pTo) { SHFILEOPSTRUCT FileOp = { 0 }; FileOp.fFlags = FOF_NOCONFIRMATION; //不出现确认对话框 FileOp.pFrom = pFrom; FileOp.pTo = pTo; FileOp.wFunc = FO_RENAME; return SHFileOperation(&FileOp) == 0; } //例如:ReNameFile(_T("e:\\my\\test.mp4"), _T("e:\\my\\test2.mp4"));
8. 分割文件路径的函数
#include <stdlib.h> 函数原型: void _splitpath(const char* path, char* drive, char* dir, char* fname, char* ext) 参数说明: path:带分解的路径 drive:得到的盘符 dir:中间路径 fname:文件名 ext:后缀名(例如“.doc”) 注意:drive,dir,fname,ext是已分配内存的指针或数组名。 若只获取某一项,其他可以用NULL。像:_splitpath(“C:\\acv.mp4”, NULL, NULL, NULL, ext) 只获取后缀名。 #include <stdlib.h> #pragma warning(disable:4996) int main() { const char* path = "D:\\a\\bb\\cc\\test.doc"; char drive[5] = { 0 }; char dir[200] = { 0 }; char fname[100] = { 0 }; char ext[10] = { 0 }; _splitpath(path, drive, dir, fname, ext); //result: //drive ="D:" dir = "\\a\\bb\\cc\\" fname="test" ext=".doc" //也可以分解相对路径,此时drive是“”。 return 0; }
9. 字符串替换 (std::string) replace_all
//字符串替换 (std::string) // 将字符串 str 中的 所有的 oldStr 替换为 newStr std::string& replace_all(std::string& str, const std::string& oldStr, const std::string& newStr) { if (str.empty() || oldStr.empty()) return str; size_t n1 = oldStr.size(); size_t n2 = newStr.size(); size_t pos = 0; while ((pos = str.find(oldStr, pos)) != std::string::npos) { str.replace(pos, n1, newStr); pos += n2; } return str; } // CString 直接有 成员函数 Replace CString str("hello world, hello China."); str.Replace(L"hello", L"good");
使用Regex
#include <regex> using namespace std; // 将字符串 str 中的 所有的与 oldStr 匹配的字符串 替换为 newStr // oldStr: 是正则表达式 std::string replace_all(const std::string& str, const std::string& oldStr, const std::string& newStr) { std::regex rx(oldStr); std::string sRet = std::regex_replace(str, rx, newStr); return sRet; } /* 使用 string str("foo is foo."); string sRet = replace_all(str, "oo", "ood"); */
10. 获取当前日期时间
#pragma warning(disable : 4996) std::string getNow() { // 基于当前系统的当前日期/时间 time_t now = time(0); tm *ltm = localtime(&now); // 输出 tm 结构的各个组成部分 char buf[20] = {0}; sprintf_s( buf, "%04d-%02d-%02d %02d:%02d:%02d", 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec); return std::string(buf); } std::string getNowDate() { // 基于当前系统的当前日期/时间 time_t now = time(0); tm *ltm = localtime(&now); // 输出 tm 结构的各个组成部分 char buf[20] = {0}; sprintf_s( buf, "%04d-%02d-%02d" , 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday ); return std::string(buf); }
-----------------------
常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。
昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。