先说一下需求,是在做录音系统中遇到的:录音文件名需要生成唯一的字符串,这个串一般由主叫号码、被叫号码、日期、时间等加上下划线作为分隔符组成,但出于兼容性考虑,某些用户希望能按他们自己的顺序来构成文件名。
除了文件名,录音文件存放路径也需要动态的配置,比如:
基础路径/日期/
或:
基础路径/被叫号码/日期/
我的解决方案是设计这样的配置文件:
// 配置项的值可使用变量,用中括号括起来的部分: [caller]-主叫号码, [callee]-被叫号码, [date]-日期(yyyymmdd), [time]-时间(hhmmss)
// 录音基础路径:
RecPath = d:\rec\[date]\[callee]\
// 文件名构成:
RecSessionFormat = [caller]_[callee]_[date]_[time]
// 连接线只可使用下划线,文件名只能使用关键字和下划线分隔符
实现一个类StringMaker,效果是这样的:
路径生成:
StringMaker* _dirMaker = new StringMaker("d:\\rec\\[date]\\[callee]\\");
string dir = _recFileMaker->Make("13902123456", "075583841234");
printf("dir=%s\n", dir.c_str()); // 输出:dir=d:\rec\20161112\075583841234\
文件名生成:
StringMaker* _sessionMaker = new StringMaker("[caller]_[callee]_[date]_[time]");
file = _sessionMaker->Make("13902123456", "075583841234");
printf("session=%s\n", file.c_str()); // 输出:13902123456_075583841234_20161112_132530
file = _sessionMaker->Make("26766666", "10086");
printf("session=%s\n", file.c_str());
还希望有个文件名反向分解的功能,即如果给定一个字符串,能够将各部份给分离出来,然后定位出文件的绝对路径。
比如,注意代码接上面部分:
char caller[100];
char callee[100];
char date[100];
char time[100];
int ret = _sessionMaker->Resolve("13312345678_10010_20161115_090856", caller, callee, date, time);
printf("Resolve: %d:\n", ret);
if (ret > 0){
printf(" caller=%s\n", caller); // 输出:13312345678
printf(" callee=%s\n", callee); // 输出:10010
printf(" date=%s\n", date); // 输出:20161115
printf(" time=%s\n", time); // 输出:090856
}
// StringMaker.cpp : C++动态配置实现。
//
# if defined(_MSC_VER)
# ifndef _CRT_SECURE_NO_DEPRECATE
# define _CRT_SECURE_NO_DEPRECATE (1)
# endif
# pragma warning(disable : 4996)
# endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <string>
#include <vector>
#include <mutex>
using namespace std;
class StringMaker
{
public:
StringMaker(const char* cfgString);
string Make(const string& pCaller, const string& pCallee);
// 反向分解:将输入id分解为各部分并输出参数(C字符串格式)
int Resolve(const char* id, char* pCaller, char* pCallee, char* pDate, char* pTime);
private:
vector<string*> items;
mutex _mutex; // 锁,多线程操作时保证安全
string caller;
string callee;
string date;
string time;
};
// 反向分解:,约定:分隔符为'_',没有其他非关键字类型
int StringMaker::Resolve(const char* id, char* pCaller, char* pCallee, char* pDate, char* pTime)
{
char ch;
char item[200];
int i = 0;
int count = 0;
_mutex.lock();
while ((ch = *id++) != '\0'){
if (ch == '_'){
if (i){
item[i] = '\0';
i = 0;
if (count + 1 > items.size()){
return(-1);
}
*items[count] = item;
// printf("count=%d: '%s'\n", count, item);
count++;
}
count++; // 分隔符本身就是一项
}
else{
item[i++] = ch;
}
}
if (i){
item[i] = '\0';
if (count + 1 > items.size()){
return(-2);
}
*items[count] = item;
// printf("count=%d: '%s'\n", count, item);
count++;
}
strcpy(pCaller, caller.c_str());
strcpy(pCallee, callee.c_str());
strcpy(pDate, date.c_str());
strcpy(pTime, time.c_str());
_mutex.unlock();
return(count);
}
StringMaker::StringMaker(const char* cfgString)
{
char ch;
char cmd[500];
int i = 0;
bool isCmd = false;
while ((ch = *cfgString++) != '\0'){
if (ch == '['){ // 命令开始
if (i){
cmd[i] = '\0';
string* s = new string(cmd);
i = 0;
items.push_back(s);
}
isCmd = true;
}
else if (ch == ']'){ // 命令结束
if (i && isCmd){
cmd[i] = '\0';
string* s = 0;
if (stricmp(cmd, "date") == 0)
s = &date;
else if (stricmp(cmd, "time") == 0)
s = &time;
else if (stricmp(cmd, "caller") == 0)
s = &caller;
else if (stricmp(cmd, "callee") == 0)
s = &callee;
if (s){
items.push_back(s);
}
} // else ERROR...
i = 0;
isCmd = false;
}
else{
cmd[i++] = ch;
}
}
if (i){
cmd[i] = '\0';
string* s = 0;
if (isCmd){
if (stricmp(cmd, "date") == 0)
s = &date;
else if (stricmp(cmd, "time") == 0)
s = &time;
else if (stricmp(cmd, "caller") == 0)
s = &caller;
else if (stricmp(cmd, "callee") == 0)
s = &callee;
}
else{
s = new string(cmd);
}
if (s){
items.push_back(s);
}
}
}
string StringMaker::Make(const string& pCaller, const string& pCallee)
{
SYSTEMTIME st;
GetLocalTime(&st);
char sdate[50];
sprintf(sdate, "%d%02d%02d", st.wYear, st.wMonth, st.wDay);
char stime[200];
sprintf(stime, "%02d%02d%02d", st.wHour, st.wMinute, st.wSecond);
string r;
_mutex.lock();
date = sdate;
time = stime;
caller = pCaller;
callee = pCallee;
for (auto p : items){
r += *p;
}
_mutex.unlock();
return(r);
}
int main(int argc, char* argv[])
{
StringMaker* _recFileMaker = new StringMaker("d:\\rec\\[date]\\[callee]\\");
string file = _recFileMaker->Make("13902123456", "075583841234");
printf("file=%s\n", file.c_str()); // 输出:dir=d:\rec\20161112\075583841234\
file = _recFileMaker->Make("26766666", "10086");
printf("file=%s\n", file.c_str());
StringMaker* _sessionMaker = new StringMaker("[caller]_[callee]_[date]_[time]");
file = _sessionMaker->Make("13902123456", "075583841234");
printf("session=%s\n", file.c_str());
file = _sessionMaker->Make("26766666", "10086");
printf("session=%s\n", file.c_str());
char caller[100];
char callee[100];
char date[100];
char time[100];
int ret = _sessionMaker->Resolve("13312345678_10010_20161115_090856", caller, callee, date, time);
printf("Resolve: %d:\n", ret);
if (ret > 0){
printf(" caller=%s\n", caller); // 输出:13312345678
printf(" callee=%s\n", callee); // 输出:10010
printf(" date=%s\n", date); // 输出:20161115
printf(" time=%s\n", time); // 输出:090856
}
return 0;
}