c++写的一个小型数据库,支持增删改查,功能是将一些长句子简化为缩写,然后通过缩写来检索并复制到剪切板

有时候我们需要将一个长的句子用一个简短的缩写记住他,比如一些常用的命令。下面的代码实现了一个map表去查询缩写对应的原文,并将原文复制到剪切板方便使用。
使用方法:
1、将以下代码在VS上编译,取出exe文件
2、将该exe文件所在目录加到环境变量里,假如该exe名为ctc.exe
3、打开cmd,设置数据文件保存路径,注意这里要全名
ctc -s "E:\ProgramEnvironment\UsefulExe\CTC\config\CtcDatabase.txt"
4、添加一条缩写记录(当然我们也可以指直接修改数据文件,添加一行就行,行格式为 缩写名 + 空格 + 原文)
ctc -a lty "when I was young I listen to the radio"
5、查询缩写原文,运行完该语句后原文"when I was young I listen to the radio"就被写入到了剪切板,我们就可以直接使用ctl-v来使用原文了
ctc --lty
6、支持value是多行的形式,格式如下,其中两个***之间的多行为value
key ***
...
...
...
***

编译方法:找到自己vs配置编译环境的脚本vcvarsall.bat(鄙人的是在C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build目录下),双击运行即可打开一个用于cl编译的命令行环境。在该环境下进入到代码所在目录,然后执行如下命令编译:
cl.exe ctc.cpp /link User32.lib advapi32.lib /Fe: ctc.exe

#include <iostream>
#include <vector>
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _CRT_SECURE_NO_WARNINGS
#define MAX_LINE 1024
#pragma warning(disable:4996)


std::string STORE_FILE;

void SetClipLTY(const std::string& str)
{
	char* clipBoardData = (char*)malloc(str.length() + 1);
	if (clipBoardData == NULL) {
		printf("malloc failed!\n");
		return;
	}
	strcpy(clipBoardData, str.c_str());

	OpenClipboard(NULL);
	EmptyClipboard();
	SetClipboardData(CF_TEXT, (HANDLE)clipBoardData);
	CloseClipboard();
	free(clipBoardData);
}



void Usage() {
	printf("Usage:\n");
	printf("prog -o/-a/-m/-d/--key\n");
	printf("-s: set the database file path\n");
	printf("-o: copy string to the clipboard\n");
	printf("-a: add a key-value map\n");
	printf("-m: modify the value of key\n");
	printf("-d: delete the key-value map\n");
	printf("-h: show all the keys in database\n");
	printf("--key: copy the value of this key to the clipboard\n");
}

// 获取第一个空白子串的起始和末尾位置,以及最后一个字符(即\n)前的空白子串的起始位置(如果不存在,则指向最后一个字符)
// 约束:str以\n结尾
void GetFirstAndLastSpaceSubStr(char *str, char* &headBegin, char* &headEnd, char* &tailBegin)
{
    for (char *p = str; *p != '\n'; p++) {
        if (isspace(*p)) {
            headBegin = headEnd = p;
            while (*(headEnd + 1) != '\n' && isspace(*(headEnd + 1))) {
                headEnd++;
            }
            break;
        }
    }

    tailBegin = str + strlen(str) - 1;
    while (tailBegin - 1 >= str && isspace(*(tailBegin - 1))) {
        tailBegin--;
    }
}


std::string QueryMap(char* key)
{
    if (*key == '\0') {
        return "";
    }
    FILE* fp = fopen(STORE_FILE.c_str(), "r");
    if (fp == NULL) {
        printf("open file %s failed!!!\n", STORE_FILE.c_str());
        return "";
    }
    char Line[MAX_LINE] = { 0 };
    while (fgets(Line, MAX_LINE, fp) != NULL) {
        if (isspace(*Line)) { // 跳过开头是空白符的行
            continue;
        }
        char *headFirstSpace = NULL;
        char *headLastSpace = NULL;
        char *tailFirstSpace = NULL;
        GetFirstAndLastSpaceSubStr(Line, headFirstSpace, headLastSpace, tailFirstSpace);
        if (headFirstSpace != NULL && headFirstSpace != tailFirstSpace) { // 只处理形如"key   xxx"的行
            *headFirstSpace = 0;
            bool isMatchKey = strcmp(Line, key) == 0;
            std::string result;
            /*考虑key ***的表示value是多行*/
            char *multiLineBeginSign = strstr(headLastSpace + 1, "***");
            if (multiLineBeginSign == headLastSpace + 1 && multiLineBeginSign + 3 == tailFirstSpace) {
                /* 读取***之后的行,直到下一个***出现 */
                while(fgets(Line, MAX_LINE, fp) != NULL && strcmp(Line, "***\n") != 0) {
                    if (isMatchKey) result += std::string(Line);
                }
            } else {
                if (isMatchKey) {
                    char *valueStart = headLastSpace + 1;
                    valueStart[strlen(valueStart) - 1] = 0;// 将末尾的\n去掉
                    result = std::string(valueStart);
                }
            }
            if (isMatchKey) {
                fclose(fp);
                return result;
            }
        }
    }
    fclose(fp);
    return "";
}

void AddMap(char* key, char* value)
{
	if (!QueryMap(key).empty()) {
		printf("the key already exists, please use -m to modify\n");
		return;
	}
	FILE* fp = fopen(STORE_FILE.c_str(), "a");
	if (fp == NULL) {
		printf("open file %s failed!!!\n", STORE_FILE.c_str());
		return;
	}
	fprintf(fp, "%s %s\n", key, value);
	fclose(fp);
}

void ModifyMap(char* key, char* value)
{
	if (QueryMap(key).empty()) {
		AddMap(key, value);
		return;
	}
	FILE* src = fopen(STORE_FILE.c_str(), "r");
	if (src == NULL) {
		printf("open file %s failed!!!\n", STORE_FILE.c_str());
		return;
	}
	FILE* dst = fopen((STORE_FILE + ".tmp").c_str(), "w");
	if (dst == NULL) {
		printf("open file %s failed!!!\n", (STORE_FILE + ".tmp").c_str());
		fclose(src);
		return;
	}
	char Line[MAX_LINE];
	while (fgets(Line, MAX_LINE, src)) {
		char* firstPos = strstr(Line, " ");
		if (firstPos != NULL) {
			*firstPos = '\0';
			if (strcmp(Line, key) == 0) {
				fprintf(dst, "%s %s\n", key, value);
			}
			else {
				*firstPos = ' ';
				fprintf(dst, "%s", Line);
			}
		}
	}
	fclose(src);
	fclose(dst);
	remove(STORE_FILE.c_str());
	rename((STORE_FILE + ".tmp").c_str(), STORE_FILE.c_str());
}

void DelMap(char* key)
{
	if (QueryMap(key).empty()) {
		return;
	}
	FILE* src = fopen(STORE_FILE.c_str(), "r");
	if (src == NULL) {
		printf("open file %s failed!!!\n", STORE_FILE.c_str());
		return;
	}
	FILE* dst = fopen((STORE_FILE + ".tmp").c_str(), "w");
	if (dst == NULL) {
		printf("open file %s failed!!!\n", (STORE_FILE + ".tmp").c_str());
		return;
	}
	char Line[MAX_LINE];
	while (fgets(Line, MAX_LINE, src)) {
		char* firstPos = strstr(Line, " ");
		if (firstPos != NULL) {
			*firstPos = '\0';
			if (strcmp(Line, key) != 0) {
				*firstPos = ' ';
				fprintf(dst, "%s", Line);
			}
		}
	}
	fclose(src);
	fclose(dst);
	remove(STORE_FILE.c_str());
	rename((STORE_FILE + ".tmp").c_str(), STORE_FILE.c_str());
}

void ShowMapKeys()
{
    FILE* fp = fopen(STORE_FILE.c_str(), "r");
    if (fp == NULL) {
        printf("open file %s failed!!!\n", STORE_FILE.c_str());
        return;
    }
    char Line[MAX_LINE] = { 0 };
    while (fgets(Line, MAX_LINE, fp) != NULL) {
        if (isspace(*Line)) { // 跳过开头是空白符的行
            continue;
        }
        char *headFirstSpace = NULL;
        char *headLastSpace = NULL;
        char *tailFirstSpace = NULL;
        GetFirstAndLastSpaceSubStr(Line, headFirstSpace, headLastSpace, tailFirstSpace);
        if (headFirstSpace != NULL && headFirstSpace != tailFirstSpace) { // 只处理形如"key   xxx"的行
            *headFirstSpace = 0;
            printf("%s\n", Line);
            /*考虑key ***的表示value是多行*/
            char *multiLineBeginSign = strstr(headLastSpace + 1, "***");
            if (multiLineBeginSign == headLastSpace + 1 && multiLineBeginSign + 3 == tailFirstSpace) {
                /* 读取***之后的行,直到下一个***出现 */
                while(fgets(Line, MAX_LINE, fp) != NULL && strcmp(Line, "***\n") != 0) {}
            }
        }
    }
    fclose(fp);
}

#define SUB_KEY "Software\\Wow6432Node\\CTC"
#define VALUE_NAME "CtcDataBaseFilePath"

bool WriteRegistryString(HKEY hKeyRoot, const std::string& subKey, const std::string& valueName, const std::string& value) {
	HKEY hKey;
	// 打开或创建注册表键
	if (ERROR_SUCCESS != RegCreateKeyExA(hKeyRoot, subKey.c_str(), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL))
	{
		return false;
	}

	// 写入 REG_SZ 值
	int result = RegSetValueExA(hKey, valueName.c_str(), 0, REG_SZ, (BYTE*)value.c_str(), value.length() + 1); // +1 包含 null 终止符
	RegCloseKey(hKey);
	return result == ERROR_SUCCESS;
}


bool ReadRegistryString(HKEY hKeyRoot, const std::string& subKey, const std::string& valueName, std::string& outValue) {
	HKEY hKey;
	// 打开注册表键
	if (ERROR_SUCCESS != RegOpenKeyExA(hKeyRoot, subKey.c_str(), 0, KEY_READ, &hKey)) {
		return false;
	}

	// 获取值大小
	DWORD dataSize = 0;
	long result = RegQueryValueExA(hKey, valueName.c_str(), nullptr, nullptr, nullptr, &dataSize);
	if (result != ERROR_SUCCESS || dataSize == 0) {
		RegCloseKey(hKey);
		return false;
	}

	// 读取值数据
	std::vector<char> buffer(dataSize);
	result = RegQueryValueExA(hKey, valueName.c_str(), nullptr, nullptr, (LPBYTE)(buffer.data()), &dataSize);
	RegCloseKey(hKey);

	if (result == ERROR_SUCCESS) {
		outValue = buffer.data();
		return true;
	}

	return false;
}


bool SetDataBaseFilePath(std::string dataBasePath) {
	return WriteRegistryString(HKEY_CURRENT_USER, SUB_KEY, VALUE_NAME, dataBasePath);
}
std::string GetDataBaseFilePath() {
	std::string dataBaseFilePath;
	ReadRegistryString(HKEY_CURRENT_USER, SUB_KEY, VALUE_NAME, dataBaseFilePath);
	return dataBaseFilePath;
}

std::string FindDir(std::string path) {
	int findPos = 0;
	if ((findPos = path.find_last_not_of('\\')) != std::string::npos) {
		return path.substr(0, findPos);
	}
	return "";
}
bool DirectoryExists(std::string dirPath) {
	DWORD attribs = GetFileAttributesA(dirPath.c_str());
	if (attribs == INVALID_FILE_ATTRIBUTES) {
		return false; // 路径无效或不存在
	}
	return (attribs & FILE_ATTRIBUTE_DIRECTORY); // 检查是否是目录属性
}

bool CreateAllDir(std::string dir)
{
	if (dir == "") {
		printf("dir is empty!\n");
		return false;
	}
	for (int i = 0; i < dir.length(); i++) {
		if (dir[i] == '\\') {
			
			std::string curDir = dir.substr(0, i);
			// 尝试创建目录
			if (!DirectoryExists(curDir)) {
				if (!CreateDirectoryA(curDir.c_str(), NULL) && (GetLastError() != ERROR_ALREADY_EXISTS)) {
					return false;  // 创建成功
				}
			}
		}
	}
	return true;
}

int main(int argc, char** argv)
{
	if (argc < 2 || argv[1][0] != '-') {
		Usage();
		return 1;
	}
	if (argv[1][1] == 's' && argv[1][2] == '\0' && argc == 3) {
		SetDataBaseFilePath(argv[2]);
		STORE_FILE = argv[2];
	} else {
		STORE_FILE = GetDataBaseFilePath();
	}



	if (STORE_FILE.empty()) {
		printf("can not get store file path\n");
		return 2;
	}

	if (!CreateAllDir(STORE_FILE)) {
		printf("can not create dir for data base file\n");
		return 3;
	}

	if (argv[1][1] == 'o' && argv[1][2] == '\0' && argc == 3) {
		SetClipLTY(argv[2]);
	}
	if (argv[1][1] == 'a' && argv[1][2] == '\0' && argc > 3) {
		AddMap(argv[2], argv[3]);
	}
	if (argv[1][1] == 'm' && argv[1][2] == '\0' && argc > 3) {
		ModifyMap(argv[2], argv[3]);
	}
	if (argv[1][1] == 'd' && argv[1][2] == '\0' && argc > 2) {
		DelMap(argv[2]);
	}
	if (argv[1][1] == 'h' && argv[1][2] == '\0') {
		ShowMapKeys();
	}
	if (argv[1][1] == '-') {
		std::string tmp = QueryMap(&argv[1][2]);
		if (!tmp.empty()) {
			printf("%s\nsuccess copy to clipboard\n", tmp.c_str());
			SetClipLTY(tmp);
		}
	}
	return 0;
}
posted @ 2025-04-19 13:55  肉肉的男朋友  阅读(16)  评论(0)    收藏  举报