为了使用正则表达式,我们或许尝试着全盘学习,
教程可见:菜鸟教程:学的不仅是技术,更是梦想!
大量的内容并不好用。我们从实用的角度,进行了如下的两个试验:
regex pattern("^.*?[(](([A-Za-z0-9_()]+),)+[)]");
smatch tmp;
string src(", (fh,)");
regex_match(src, tmp, pattern);
for (auto it = tmp.begin(); it < tmp.end(); it++)
cout << *it << endl;
return 0;
试验输出:
, (fh,)
fh,
fh
这个试验告诉我们,C++可以进行多层小括号的匹配。
regex pattern("^.*?[(]((([A-Za-z0-9_()]+),){1,})[)]");
smatch tmp;
string src(", (asd,fh,)");
regex_match(src, tmp, pattern);
for (auto it = tmp.begin(); it < tmp.end(); it++)
cout << *it << endl;
return 0;
输出结果:这个试验告诉我们,C++正则,尽管可以利用次数限制,使得表达式完成匹配,但重复匹配的部分仅保留最后一次结果,所以在建立表格的时候,我们不能利用这样的语法实现任意列数的表格。
, (asd,fh,)
asd,fh,
fh,
fh
Interpreter是一个通用接口,接受Input函数带来的以非空字符开始、分号结尾的字符串。然后利用switch
的语句进行分流。这个简易程序支持以下操作:
create database
create table
use
insert
update
delete
where
由于同样的几个操作也在流操作文件中出现,为了避免重名,也为了避免冗长的命名,使用命名空间实在是一个非常好的选择。
几个要点:
程序如下:
//interpreter.hpp
/**
* @file: interpreter.hpp
* @author: fhn
* @date: 4/20
* @version: 1.0 to be improved : a function which formats a string into pieces of strings without spaces in them
* @description: receiving params from the ui::Input(),
* containing the main parts of interpreters
* in different functions.
*/
//--------------------------------------------------------------------------------------------
#ifndef INTERPRETER_GUARD
#define INTERPRETER_GUARD
#include
#include
#include
#include
#include
#include
#include "in_out.hpp"
//--------------------------------------------------------------------------------------------
void Interpret(const std::string&);
#ifndef CLAUSEGUARD
#define CLAUSEGUARD
struct Clause
{
std::string name;
std::string op;
std::string value;
Clause(std::string a, std::string b, std::string c) :name(a), op(b), value(c){ };
Clause() : name(), op(), value(){ }
};
#endif
/**
* @author: fhn
* @date: 4/21
* @description: a namespace targeted for Interpret();
* @version:
*/
namespace sql_itp{
using std::string;
void trim(string&);
//free of where
/**
* @author: fhn
* @date: 4/22
* @description: call in_out::Create(database_name) to create a database(as a filefolder) or table(file)
*/
void Create(char mode, const string& src);
/**
* @author: fhn
* @date: 4/22
* @description: call in_out::Use(database_name), impl by changing cur_db.
*/
void Use(const string& src);
/**
* @author: fhn
* @date: 4/22
* @description: call in_out::Insert(table_name, )
*/
void Insert(const string& src);
//fucking blessed with where clause
/**
* @author: fhn
* @date: 4/25
* @description: return a Clause obj including info of Where.
*/
Clause Where(const string& src);
void Select(const string& src);
void Update(const string& src);
void Delete(const string& src);
} // namespace sql_itp
#endif
其实常引用并无,必要毕竟产生了拷贝开销。
最后的流清除操作可以在异常部分进行。
void Interpret(const std::string& raw)
{
using std::string; using std::stringstream;
string judge;
stringstream ss(raw);
ss >> judge;
switch(judge[0])
{
case 'c': case 'C':
ss >> judge;
sql_itp::Create(judge[0], raw);
break;
case 'i': case 'I':
ss >> judge;
sql_itp::Insert(raw);
break;
case 'u': case 'U':
if (judge[1] == 's' || judge[1] == 'S')
sql_itp::Use(raw);
else sql_itp::Update(raw);
break;
case 's': case 'S':
sql_itp::Select(raw);
break;
case 'd': case 'D':
sql_itp::Delete(raw);
break;
error("sentence syntax went wrong."); fflush(stdin);
}
#ifdef _LOC_
std::clog << "finished once" << std::endl;
#endif
fflush(stdin);
}
由于传入的raw字符串可能存在非法的空格,我们增加了如下的函数
void trim(string & src)
{
src.erase(0, src.find_first_not_of(" "));
src.erase(src.find_last_not_of(" ")+1);
}
这个函数是STL中find算法和string字符串处理的一个好例子。
发生语句解释,并提取有效信息传递给对应的I/O函数。
要点:
peek()
函数的使用帮助我们免去计算的麻烦,便利地实现忽略前导无效字符的操作。compare()
辅助确定具体类型。in_out.hpp
中定义的col_info
结构传递。void Create(char mode, const string& src)
{
if (mode == 'd' || mode == 'D')
{
std::regex pattern{"^.*?create.*?database.*?(\\w+).*?;$", std::regex::icase};
std::smatch mat;
if (!regex_match(src, mat, pattern))
{ error("create database : syntax wrong"); return; }
in_out::CreateDatabase(mat[1]);
}
else if (mode == 't' || mode == 'T')//
{
std::regex pattern{"^.*?create.*?Table.*?(\\w+)\\s*[(]\\s*(.*)[)].*?;.*?$", std::regex::icase};
//table name must be in the alphas, nums and '_'
std::smatch mat;
if (!regex_match(src, mat, pattern))
{ error("create table : syntax wrong"); return;}//mat[1] is tablename, mat[2] is the param of columns.
#ifdef _LOC_
else
std::clog << "create table matched" << std::endl;
#endif
in_out::ColInfo param;
std::string name, type;
std::stringstream ss(mat[2]);
while (ss.peek() != EOF) // if using "while (ss)", the eof won't be trigered in time.
{
while (ss.peek() == ' ') ss.ignore();
getline(ss, name, ' ');
while (ss.peek() == ' ') ss.ignore();// ignore the heading spaces.
getline(ss, type, ',');
trim(name); trim(type);
if (type[0] == 'i' || type[0] == 'I')
{
if (!type.compare(0,3, "int", 0,3) && !type.compare(0,3, "INT", 0, 3))
{ error("var table type illegal"); return;}
else param.AddCol(name, 0);
}
else if (type[0] == 'v' || type[0] == 'V') //this may be improved : in the form of 'varchar (20)' isn;t supported
//2.1 : now supported.
{
int cnt = 7, ans = 0;
if (!(type.compare(0, 7, "varchar", 0, 7)||type.compare(0, 7, "VARCHAR", 0, 7)))
{ error("var table type illegal"); return;}
for (; cnt < type.size() && (!std::isdigit(type[cnt])); cnt++);
if (cnt != type.size())
while (std::isdigit(type[cnt]))
ans = ans * 10 + (type[cnt]-'0'), cnt++;
else { error("var table type illegal"); return;}
param.AddCol(name, ans);
}
else
{ error("var table type illegal"); return;}
}
#ifdef _LOC_
std::clog << "create table prepared" << std::endl << std::endl;
#endif
in_out::CreateTable(mat[1], param);
}
else error("#ERROR: create table mode wrong.");
}
void Use(const string& src)
{
std::regex pattern{"^.*?use.*?(\\w+).*?;", std::regex::icase};
std::smatch mat;
if (!regex_match(src, mat, pattern))
{ error("use sentence wrong"); return; };
string tmp = mat[1].str();
trim(tmp);
in_out::Use(tmp);
}
一次插入一行,所有数据都用string表示,传出使用vector
void Insert(const string& src)
{
std::regex pattern{"^.*?insert.*?into.*?(\\w+).*?value.*?[(]\\s*(.*)[)].*?;.*?$", std::regex::icase};
std::smatch mat;
if (!regex_match(src, mat, pattern))
{ error("insert syntax wrong: whole sentence"); return; }
std::string name(mat[1]);
std::stringstream ss(mat[2]);
std::vector<string> vec_param;
std::string tmp;
while (ss.peek() != EOF)
{
while (ss.peek() == ' ') ss.ignore();
getline(ss, tmp, ',');
trim(tmp);
vec_param.push_back(tmp);
}
in_out::Insert(name, vec_param);
}
以下的三个语句都要一定一定程度上依赖where子句的解释,所以,我们先给出where子句的结构
/**
* @author: fhn
* @date: 4/25
* @description: transform a string of 'where clause' into a Clause obj(which contains the info of it).
* @input: a string without front and rear spaces; started with where.
* if a void string in, directly return an obj (0, 0, 0)
* @version: 1.0
* v1.1: the * and + cause the regex to go wrong, improve the intercommunication of regex function cut the ';'
*/
Clause Where(const string& src)
{
std::regex pattern{"^.*?where\\s+(\\w+)\\s*([><=!]{1,2})\\s*(.+?)\\s*$", std::regex::icase};
std::smatch mat;
if (regex_match(src, mat, pattern))
return Clause{mat[1].str(), mat[2].str(), mat[3].str()};
return Clause();
}
select同样也需要
void Select(const string& src)
{
std::regex pattern{"^.*?select\\s*(.*)\\s*from\\s+(\\w+)\\s*(where.*?)*\\s*;.*?$", std::regex::icase};
std::smatch mat;
if (!regex_match(src, mat, pattern))
{ error("select syntax wrong: whole sentence"); return;};
std::string name(mat[2]);
std::stringstream ss(mat[1]);
std::vector<string> vec_param;
std::string tmp;
while (ss.peek() != EOF)
{
getline(ss, tmp, ',');
trim(tmp);
vec_param.push_back(tmp);
}
in_out::Select(name, vec_param, Where(mat[3].str()));
}
void Update(const string& src)
{
std::regex pattern{"^.*?update\\s+(\\w+)\\s+set\\s+(.*?)\\s*=\\s*(.+?)\\s+(where.*?)\\s*;.*?$", std::regex::icase};
std::smatch mat;
if (!regex_match(src, mat, pattern))
{ error("#ERROR: update syntax wrong: whole sentence"); return;};
in_out::Update(mat[1].str(), mat[2].str(), mat[3].str(), Where(mat[4].str()));
}
void Delete(const string& src)
{
std::regex pattern{"^.*?delete\\s+from\\s+(\\w+)\\s+(where.*?)\\s*;.*?$", std::regex::icase};
std::smatch mat;
if (!regex_match(src, mat, pattern))
{ error("delete sentence wrong"); return; };
in_out::Delete(mat[1].str(), Where(mat[2].str()));
}