1 解析简单 SQL 语句

在 C++ 中,可以使用标准库中的<regex>来解析SQL语句。不过,需要注意的是,SQL 语句的结构非常复杂,涉及到多个部分(如 SELECT、FROM、WHERE 等),并且每个部分可能有不同的语法规则。因此,完全解析一个 SQL 语句是一个复杂的任务,通常需要使用专门的 SQL 解析器库。

不过,如果只是想简单地提取 SQL 语句的某些部分(例如,提取表名或列名),可以使用正则表达式来实现。如下是一个简单的样例,展示了如何使用 C++ 正则表达式来解析 SQL SELECT 语句中的表名和列名:

#include <iostream>  
#include <string>  
#include <regex>  

int main() 
{
	std::string sql = "SELECT column1, column2 FROM table_name WHERE condition;";

	// 正则表达式模式,用于匹配表名和列名  
	std::regex tablePattern(R"(FROM\s+(\w+))", std::regex_constants::icase);
	std::regex columnPattern(R"(\bSELECT\s+(\w+)(?:,\s*(\w+))*)", std::regex_constants::icase);

	// 使用sregex_token_iterator提取表名  
	std::sregex_token_iterator iter(sql.begin(), sql.end(), tablePattern, 1);
	std::sregex_token_iterator end;
	for (; iter != end; iter++) 
	{
		std::cout << "table name: " << *iter << std::endl;
	}

	// 使用 std::smatch 提取列名  
	std::string columnStr = "";
	std::smatch match;
	bool found = std::regex_search(sql, match, columnPattern);
	if (found)
	{
		for (size_t i = 1; i < match.size(); i++)
		{
			std::cout << "column name: " << match[i].str() << std::endl;
		}
	}	

	return 0;
}

上面代码的输出为:

table name: table_name
column name: column1
column name: column2

上面代码中的正则表达式:

std::regex tablePattern(R"(FROM\s+(\w+))", std::regex_constants::icase);  
std::regex columnPattern(R"(\bSELECT\s+(\w+)(?:,\s*(\w+))*)", std::regex_constants::icase);

其含义为:
tablePattern:用于匹配 SQL 查询中的表名。它查找以"FROM"开头,后跟一个或多个空格,然后是一个或多个单词字符(表名)的模式。
columnPattern:用于匹配 SQL 查询中的列名。它查找以"SELECT"开头,后跟一个或多个空格,然后是一个或多个单词字符(第一个列名),可能后跟零个或多个由逗号、空格和另一个单词字符组成的序列(其他列名)的模式。
std::regex_constants::icase:这是一个标志,表示在匹配时不区分大小写。

随后使用 sregex_token_iterator 来遍历 SQL 字符串中与 tablePattern 匹配的部分。这里, 1 作为参数传递给 sregex_token_iterator 的构造函数,表示只对匹配到的第一个捕获组(即括号中的内容)感兴趣。因此,它将只提取表名。

然后使用 std::regex_search 来查找与 columnPattern 匹配的部分。如果找到了匹配项,它将存储在 match 对象中。最后遍历 match 对象中的所有捕获组,并打印出列名。(注意在 columnPattern 中使用了非捕获组标识 ?: ,这样可以避免捕获到 column1, column2 的整体字符串)

2 提取四则运算中的数字和运算符

处理四则运算的完整解析器是相当复杂的,因为需要考虑运算符优先级、括号、空格和其他可能的输入问题。但是,使用正则表达式可以帮助识别和抽取数学表达式的各个部分。

如下是一个简单样例,它使用正则表达式来识别和提取四则运算表达式中的数字和运算符:

#include <iostream>  
#include <regex>  
#include <string>  
#include <vector>  

int main() 
{
	std::string expression = "32 + 4 * 2.7 / ( 1.09 - 5 )";

	// 正则表达式匹配数字和运算符  
	std::regex pattern(R"([-+]?\d+\.\d+|[-+]?\d+|[-+*/()])");

	// 存储匹配结果  
	std::vector<std::string> matches;

	// 查找所有匹配项  
	auto begin = std::sregex_iterator(expression.begin(), expression.end(), pattern);
	auto end = std::sregex_iterator();

	for (std::sregex_iterator i = begin; i != end; i++) 
	{
		std::smatch match = *i;
		matches.push_back(match.str());
	}

	// 输出匹配结果  
	for (const auto& match : matches) 
	{
		std::cout << match << std::endl;
	}

	return 0;
}

上面代码的输出为:

32
+
4
*
2.7
/
(
1.09
-
5
)

这个示例中的正则表达式 [-+]?\d+\.\d+|[-+]?\d+|[-+*/()] 匹配以下类型的字符串:

[-+]?\d+\.\d+:匹配可能带有正负号的小数(例如 “3.14” 或 “-1.9”)。
[-+]?\d+:匹配可能带有正负号的整数(例如 “12” 或 “-1”)。
[-+*/()]:匹配基本的四则运算符和括号。
这个程序将输出表达式中的所有数字和运算符。

3 文本搜索与替换

在 C++ 中,可以使用<regex>库来进行正则表达式的文本搜索和替换。下面是一个简单的样例,展示如何使用 C++ 正则表达式库来搜索一个字符串中的特定模式,并将其替换为另一个字符串。

假设有一个文本字符串,需要找到其中所有的单词"hello"并将其替换为"ok"。

#include <iostream>  
#include <regex>  
#include <string>  

int main() 
{
	// 原始文本  
	std::string text = "hello test, hello example";

	// 正则表达式模式,匹配单词"hello"  
	// \b 表示单词边界,\w+ 匹配一个或多个单词字符  
	std::regex pattern(R"(\bhello\b)");

	// 替换字符串  
	std::string replacement = "ok";

	// 执行替换  
	std::string result = std::regex_replace(text, pattern, replacement);

	// 输出结果  
	std::cout << result << std::endl;

	return 0;
}

上面代码的输出为:

ok test, ok example

在上面代码中,定义了一个正则表达式 pattern,它匹配单词边界(\b)之间的"hello"单词。然后使用 std::regex_replace 函数将匹配到的每个"hello"替换为"ok"。
注意:std::regex_replace 默认行为就是全局替换。如果只想替换第一个匹配项,可以传递一个额外的参数 std::regex_constants::format_first_only 给 std::regex_replace 函数:

// 只替换第一个匹配项  
std::string resultFirst = std::regex_replace(text, pattern, replacement, std::regex_constants::format_first_only);
std::cout << resultFirst << std::endl;

这将输出:

ok test, hello example

4 数据验证与过滤

在C++中,正则表达式可以用于数据验证和过滤,以确保输入数据符合特定的格式或标准。这通常涉及到检查字符串是否符合特定的模式,如电子邮件地址、电话号码、邮政编码等。下面是一个使用C++正则表达式进行数据验证和过滤的样例。

假设需要验证一个字符串是否是一个有效的电子邮件地址(如 user@example.com),则可以使用正则表达式来检查这个格式:

#include <iostream>  
#include <regex>  
#include <string>  

bool isValidEmail(const std::string& email)
{
	// 正则表达式,匹配常见的电子邮件地址格式  
	std::regex pattern(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})");

	// 使用std::regex_match进行匹配  
	return std::regex_match(email, pattern);
}

int main() {
	// 待验证的电子邮件地址列表  
	std::vector<std::string> emails = {
		"valid1@example.com",
		"invalid1.email@",
		"invalid2@example"
	};

	// 验证每个电子邮件地址并输出结果  
	for (const auto& email : emails)
	{
		if (isValidEmail(email)) 
		{
			std::cout << email << " is a valid email address.\n";
		}
		else 
		{
			std::cout << email << " is not a valid email address.\n";
		}
	}

	return 0;
}

上面代码的输出为:

valid1@example.com is a valid email address.
invalid1.email@ is not a valid email address.
invalid2@example is not a valid email address.

在上面代码中,定义了一个 isValidEmail 函数,它接受一个字符串参数并返回一个布尔值,指示该字符串是否是一个有效的电子邮件地址。接下来使用了一个正则表达式来匹配电子邮件地址的常见格式,并使用 std::regex_match 函数来检查输入字符串是否符合这个模式。

5 字符串格式化与美化

在 C++ 中,正则表达式不仅可以用于数据验证和过滤,还可以用于字符串的格式化与美化。这通常涉及到对字符串进行搜索、替换、分割或重组,以使其符合特定的格式要求或提升可读性。以下是一些使用 C++ 正则表达式进行字符串格式化与美化的例子。

5.1 去除字符串中的多余空格

#include <iostream>  
#include <regex>  
#include <string>  

std::string removeExtraSpaces(const std::string& input)
{
	// 正则表达式,匹配一个或多个连续的空格  
	std::regex pattern(R"(\s+)");

	// 使用空格替换所有匹配的连续空格  
	std::string result = std::regex_replace(input, pattern, " ");

	return result;
}

int main() 
{
	std::string text = "this   is   a   test";
	std::string formattedText = removeExtraSpaces(text);
	std::cout << formattedText << std::endl;
	return 0;
}

上面代码的输出为:

this is a test

5.2 去除字符串开头和结尾的空白字符

可以使用正则表达式来实现trim功能,即去除字符串开头和结尾的空白字符:

#include <iostream>  
#include <regex>  
#include <string>  

// 使用正则表达式去除字符串两端的空白字符  
std::string trim(const std::string& str) 
{
	// 正则表达式匹配字符串开头和结尾的空白字符  
	std::regex whitespace("^\\s+|\\s+$");

	// 使用空字符串替换匹配到的空白字符  
	std::string result = std::regex_replace(str, whitespace, "");

	return result;
}

int main() {
	std::string text = "   Hello, World!   ";
	std::string trimmedText = trim(text);
	std::cout << "Trimmed text: '" << trimmedText << "'\n";
	return 0;
}

上面代码的输出为:

Trimmed text: 'Hello, World!'

5.3 分割字符串为单词或子串

#include <iostream>  
#include <regex>  
#include <string>  
#include <vector>  

std::vector<std::string> splitString(const std::string& input, char delimiter) 
{
	std::regex pattern(std::string(1, delimiter) + "+");
	std::sregex_token_iterator iter(input.begin(), input.end(), pattern, -1);
	std::sregex_token_iterator end;
	std::vector<std::string> tokens(iter, end);
	return tokens;
}

int main() 
{
	std::string text = "word1,word2,word3";
	std::vector<std::string> words = splitString(text, ',');
	for (const auto& word : words)
	{
		std::cout << word << std::endl;
	}
	return 0;
}

上面代码的输出为:

word1
word2
word3

上面代码使用了 std::regex_replace 来替换字符串中的模式,std::sregex_token_iterator 来分割字符串。

03-03 18:14