在第三方正则工具中可以正常匹配的正则表达式和目标串,到了正式工程中,用regcomp设置正则没问题。但是regexec时,得不到正确的匹配结果。
在排查过程中,写了测试程序, 如果正则较简单,匹配结果正确。如果正则比较复杂,匹配结果不正确。
按照https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215的说法,将比较高级的正则语法换成等价的比较基本的正则语法. 这下过了.
难道linux的正则库这么衰,不至于啊。
再排查,发现工程中用法是用文本文件中读取一条一条的行,作为一个一个的正则表达式。单步时,打出正则表达式,发现是\n结尾的字符串。就试着在读文件取得正则表达式后,如果是\n结尾,就换成\0结尾,这下清静了. O了。
在解决这个bug的过程中,写了一个测试工具,用来检测写在文本文件中的正则表达式和要检测的目标字符串是否匹配。这样在出问题之前,就可以将正则表达式记录集合所在的文件校验正确,很适合运维的同事更换正则数据文件时用。
src_regex_rule_file_parser.7z
##代表注释
#代表要匹配的字符串
不带#,不带##的行当作正则表达式
每块正则数据之间用空行分开
## @file test_regex_rule.dat
## match
#select * from abc where 1=1
.*\s+[0-9]\s*=\s*[0-9]
## not match
#carry
\b[Cc][Aa][Rr]\b
## match
#carry
\b[Cc][Aa][Rr]
## match
#rycar
[Cc][Aa][Rr]\b
## match
#Hello, someone name is Ben. do you hear me?
Ben
## match
#sales1.xls
sales.
## match
#wsales1.xls
sales.
## match
## regex中 '.'代表一个字符
#wsales1xls
sales.
root@debian750devmin:/home/test# ls
总用量 324
-rw-r--r-- 1 root root 1532 8月 8 15:19 ls_regex.cpp
-rw-r--r-- 1 root root 563 7月 17 17:27 ls_regex.h
-rw-r--r-- 1 root root 56784 8月 9 00:41 ls_regex.o
-rw-r--r-- 1 root root 7044 8月 8 17:13 main.cpp
-rw-r--r-- 1 root root 108632 8月 9 00:41 main.o
-rw-r--r-- 1 root root 1302 8月 8 16:14 Makefile
-rw-r--r-- 1 root root 1344 11月 14 2017 my_syslog.cpp
-rw-r--r-- 1 root root 4943 3月 11 15:07 my_syslog.h
-rw-r--r-- 1 root root 18432 8月 9 00:41 my_syslog.o
-rw-r--r-- 1 root root 187 8月 8 16:19 readme.txt
-rwxrwxr-x 1 root root 101111 8月 9 00:41 test_regex*
-rw-r--r-- 1 root root 368 8月 9 00:40 test_regex_rule.dat
root@debian750devmin:/home/test# ./test_regex ./test_regex_rule.dat
--------------------------------------------------------------------------------
regex_filter = [.*\s+[0-9]\s*=\s*[0-9]]
sz_string_match = [select * from abc where 1=1]
--------------------------------------------------------------------------------
match ok!
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
regex_filter = [\b[Cc][Aa][Rr]\b]
sz_string_match = [carry]
--------------------------------------------------------------------------------
match error
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
regex_filter = [\b[Cc][Aa][Rr]]
sz_string_match = [carry]
--------------------------------------------------------------------------------
match ok!
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
regex_filter = [[Cc][Aa][Rr]\b]
sz_string_match = [rycar]
--------------------------------------------------------------------------------
match ok!
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
regex_filter = [Ben]
sz_string_match = [Hello, someone name is Ben. do you hear me?]
--------------------------------------------------------------------------------
match ok!
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
regex_filter = [sales.]
sz_string_match = [sales1.xls]
--------------------------------------------------------------------------------
match ok!
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
regex_filter = [sales.]
sz_string_match = [wsales1.xls]
--------------------------------------------------------------------------------
match ok!
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
regex_filter = [sales.]
sz_string_match = [wsales1xls]
--------------------------------------------------------------------------------
match ok!
--------------------------------------------------------------------------------
就按照si中的顺序贴了,不整理了。
// @file ls_regex.cpp
#include
#include "ls_regex.h"
void clear_string(std::string& str)
{
std::string str_tmp = "";
str.swap(str_tmp);
}
ls_regex::ls_regex()
{
m_is_valid_filter = false;
m_str_filter = "";
m_str_error = "";
}
ls_regex::~ls_regex()
{
if (m_is_valid_filter) {
regfree(&m_reg);
}
}
void ls_regex::setfilter(const char* psz_filter)
{
int i_rc = 0;
char buf[REGEX_BUFFER_SIZE] = {'\0'};
clear_string(m_str_filter);
m_str_filter = (NULL != psz_filter) ? psz_filter : "";
// filter串必须以\0结尾
std::replace(m_str_filter.begin(), m_str_filter.end(), '\r', '\0');
std::replace(m_str_filter.begin(), m_str_filter.end(), '\n', '\0');
if (m_is_valid_filter) {
regfree(&m_reg);
}
m_str_error = "";
i_rc = regcomp(&m_reg, m_str_filter.c_str(), REG_ICASE | REG_NOSUB | REG_EXTENDED);
if (REG_NOERROR != i_rc) {
regerror(i_rc, &m_reg, buf, sizeof(buf));
m_str_error = buf;
}
m_is_valid_filter = (0 == i_rc);
}
std::string ls_regex::get_error_msg()
{
return m_str_error;
}
bool ls_regex::is_valid_filter()
{
return m_is_valid_filter;
}
bool ls_regex::is_match(const char* psz_regex)
{
int i_rc = 0;
if (NULL == psz_regex) {
return false; // not match
}
if (!m_is_valid_filter) {
return true; // if filter is invalid or not set, return as match
}
i_rc = regexec(&m_reg, psz_regex, 0, NULL, 0);
return (REG_NOERROR == i_rc);
}
// @file ls_regex.h
#ifndef __LS_REGEX_H__
#define __LS_REGEX_H__
#include
#include
#include
#include
#define REGEX_BUFFER_SIZE 512
class ls_regex {
public:
ls_regex();
virtual ~ls_regex();
void setfilter(const char* psz_filter);
bool is_match(const char* psz_regex);
bool is_valid_filter();
std::string get_error_msg();
private:
regex_t m_reg;
std::string m_str_filter;
bool m_is_valid_filter;
std::string m_str_error;
};
#endif // #ifndef __LS_REGEX_H__
// @file main.cpp
// view date time
// date "+DATE: %m/%d/%y%nTIME: %H:%M:%S"
// set date time
// date -s "2018-3-13 14:25:00"
#include
#include
// #include
#include
#include
#include
#include
#include
#include
#include "my_syslog.h"
#include "ls_regex.h"
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long ulong;
typedef unsigned long long ull;
#define LINE80 "--------------------------------------------------------------------------------"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) \
if (NULL != (p)) { \
delete (p); \
(p) = NULL; \
}
#endif // #ifndef SAFE_DELETE
typedef enum e_file_read_status {
e_file_read_status_ready = 1, // 当前状态是准备就绪
e_file_read_status_over_string_to_match = 2, // 当前状态是读取可以匹配的字符串
e_file_read_status_over_string_to_filter = 3, // 当前状态是读取正则表达式
}E_FILE_READ_STATUS;
class TAG_REGEX_RULES_UNIT
{
public:
char sz_string_match[1024];
char sz_regex_filter[1024];
ls_regex* p_regex_filter_pattern;
public:
TAG_REGEX_RULES_UNIT()
{
memset(this->sz_string_match, 0, sizeof(this->sz_string_match));
memset(this->sz_regex_filter, 0, sizeof(this->sz_regex_filter));
this->p_regex_filter_pattern = new ls_regex();
}
virtual ~TAG_REGEX_RULES_UNIT()
{
if (NULL != this->p_regex_filter_pattern) {
delete this->p_regex_filter_pattern;
this->p_regex_filter_pattern = NULL;
}
}
};
bool load_regex_rules_file(const char* psz_file_path_name, std::vector & vec_regex_rules);
void init();
void uninit();
int fn_test(int argc, char** argv);
int main(int argc, char** argv)
{
system("clear");
init();
if (2 != argc) {
printf("usage : this.exe pathname_for_regex_rules_file\n");
}
fn_test(argc, argv);
uninit();
return EXIT_SUCCESS;
}
/** run result
*/
void init()
{
ns_syslog::open_syslog("test_new");
// 设置控制变量中的日志条件, 实际应用中, 是从配置文件读取的控制开关
ns_syslog::g_log_condition.b_EMERG = false;
ns_syslog::g_log_condition.b_CRIT = true;
ns_syslog::g_log_condition.b_ALERT = true;
ns_syslog::g_log_condition.b_ERR = true;
ns_syslog::g_log_condition.b_WARNING = true;
ns_syslog::g_log_condition.b_NOTICE = true;
ns_syslog::g_log_condition.b_INFO = true;
ns_syslog::g_log_condition.b_DEBUG = true;
// 根据控制变量, 设置日志的mask
// 在实际应用中, 这里可以是动态设置, e.g. 配置文件检测线程发现配置变了, 需要变更某些级别的日志记录结果
ns_syslog::set_log_level(
ns_syslog::g_log_condition.b_EMERG,
ns_syslog::g_log_condition.b_ALERT,
ns_syslog::g_log_condition.b_CRIT,
ns_syslog::g_log_condition.b_ERR,
ns_syslog::g_log_condition.b_WARNING,
ns_syslog::g_log_condition.b_NOTICE,
ns_syslog::g_log_condition.b_INFO,
ns_syslog::g_log_condition.b_DEBUG);
}
void uninit()
{
ns_syslog::close_syslog();
}
int fn_test(int argc, char** argv)
{
std::vector vec_regex_rules;
std::vector ::iterator it;
TAG_REGEX_RULES_UNIT* p_tmp = NULL;
if (2 != argc) {
return EXIT_FAILURE;
}
if (load_regex_rules_file(argv[1], vec_regex_rules)) {
for (it = vec_regex_rules.begin(); it != vec_regex_rules.end(); it++) {
// test rules for match
p_tmp = *it;
if ((NULL != p_tmp) && (NULL != p_tmp->p_regex_filter_pattern)) {
printf("%s\n", LINE80);
printf("regex_filter = [%s]\n", p_tmp->sz_regex_filter);
printf("sz_string_match = [%s]\n", p_tmp->sz_string_match);
printf("%s\n", LINE80);
if (p_tmp->p_regex_filter_pattern->is_match(p_tmp->sz_string_match)) {
printf("match ok!\n");
} else {
printf("match error\n");
// https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215
// try to fix, if fixed ok, show user the filter after fix
}
printf("%s\n", LINE80);
}
}
}
// clear vec_regex_rules
for (it = vec_regex_rules.begin(); it != vec_regex_rules.end(); it++) {
p_tmp = *it;
SAFE_DELETE(p_tmp);
*it = NULL;
}
vec_regex_rules.clear();
return EXIT_SUCCESS;
}
bool load_regex_rules_file(const char* psz_file_path_name, std::vector & vec_regex_rules)
{
bool b_rc = false;
bool error_happen = false;
FILE* pf = NULL;
char buf[1024] = {'\0'};
char* line = NULL;
int line_len = 0;
TAG_REGEX_RULES_UNIT* p_regex_rules = NULL;
// char* psz_tmp = NULL;
// 文件格式 : 文件块(#可以匹配的字符串, 正则表达式,空行) * N
// e.g.
// #后面直接带可以匹配的字符串
// #hello, word
// [a-z]
//
E_FILE_READ_STATUS cur_status = e_file_read_status_ready;
do {
if (NULL == psz_file_path_name) {
break;
}
pf = fopen(psz_file_path_name, "r");
if (NULL == pf) {
error_happen = true;
break;
}
while (1) {
memset(buf, 0, sizeof(buf));
line = fgets(buf, sizeof(buf) - 1, pf);
if (NULL == line) {
break;
}
line_len = strlen(line);
// 去掉读回行的回车
if (line_len > 0) {
switch (line[line_len - 1]) {
case '\r':
case '\n':
line[line_len - 1] = '\0';
line_len--;
break;
default:
break;
}
}
switch (cur_status) {
case e_file_read_status_ready: {
if (NULL == p_regex_rules) {
p_regex_rules = new TAG_REGEX_RULES_UNIT();
}
// read_status_string_to_match
if (NULL != p_regex_rules) {
if (line_len < 2) {
break;
}
if (buf[0] == '#') {
if (buf[1] == '#') {
// ## xxx 是注释
break;
}
// #xxx 是要匹配的串
strcpy(p_regex_rules->sz_string_match, buf + 1);
cur_status = e_file_read_status_over_string_to_match;
}
}
}
break;
case e_file_read_status_over_string_to_match: {
if (NULL != p_regex_rules) {
if ((buf[0] != '#') && (line_len > 0)) {
strcpy(p_regex_rules->sz_regex_filter, buf);
if (NULL != p_regex_rules->p_regex_filter_pattern) {
p_regex_rules->p_regex_filter_pattern->setfilter(p_regex_rules->sz_regex_filter);
if (!p_regex_rules->p_regex_filter_pattern->is_valid_filter())
{
MYLOG_E("p_regex_rules->sz_string_match = [%s], regcomp error %s",
p_regex_rules->sz_string_match,
p_regex_rules->p_regex_filter_pattern->get_error_msg().c_str());
SAFE_DELETE(p_regex_rules);
} else {
vec_regex_rules.push_back(p_regex_rules);
p_regex_rules = NULL;
}
cur_status = e_file_read_status_over_string_to_filter;
}
}
}
}
break;
case e_file_read_status_over_string_to_filter: {
if (line_len <= 0) {
cur_status = e_file_read_status_ready;
}
}
break;
default:
break;
}
}
fclose(pf);
pf = NULL;
b_rc = (false == error_happen);
} while (0);
SAFE_DELETE(p_regex_rules);
return b_rc;
}
# ==============================================================================
# @file makefile
# ==============================================================================
BIN = test_regex
LINE80 = --------------------------------------------------------------------------------
CC = g++ -std=c++98
CFLAGS = -Wall -g
INC = -I.
LIBS = -lstdc++ -pthread -lpthread -lm -fPIC
LIBPATH = -L/usr/lib/ -L/usr/local/lib/ -L./lib/
SHLIBS =
DEPEND_CODE_DIR = ./empty_dir \
DEPEND_CODE_SRC = $(shell find $(DEPEND_CODE_DIR) -name '*.cpp')
DEPEND_CODE_OBJ = $(DEPEND_CODE_SRC:.cpp=.o)
ROOT_CODE_SRC = $(shell find ./ -name '*.cpp')
ROOT_CODE_OBJ = $(ROOT_CODE_SRC:.cpp=.o)
SUB_CODE_DIR = ./socket_easy
SUB_CODE_SRC = $(shell find $(SUB_CODE_DIR) -name '*.cpp')
SUB_CODE_OBJ = $(SUB_CODE_SRC:.cpp=.o)
clean:
clear
@echo $(LINE80)
@echo make clean
rm -f $(BIN) $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
rm -rf /usr/lib/$(BIN)
rm -rf ./$(BIN)
all:$(BIN)
@echo $(LINE80)
@echo make all
chmod 777 $(BIN)
find . -name $(BIN)
$(BIN) : $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
$(CC) $(CFLAGS) -o $@ $^ $(SHLIBS) $(INC) $(LIBPATH) $(LIBS)
.cpp.o:
$(CC) -c $(CFLAGS) $^ -o $@ $(INC) $(LIBPATH) $(LIBS)
rebuild:
make clean
@echo $(LINE80)
make all
chmod 775 ./$(BIN)
// @file my_syslog.cpp
// @brief syslog日志宏的实现
#include "my_syslog.h"
namespace ns_syslog {
TAG_LOG_CONDITION g_log_condition;
void open_syslog(const char* pszLogOwner)
{
openlog(((NULL != pszLogOwner) ? pszLogOwner : "my_syslog"), LOG_NOWAIT | LOG_PID, LOG_LOCAL1);
}
void set_log_level(
bool b_EMERG,
bool b_CRIT,
bool b_ALERT,
bool b_ERR,
bool b_WARNING,
bool b_NOTICE,
bool b_INFO,
bool b_DEBUG)
{
int i_mask = 0;
if (b_EMERG) {
// LOG_EMERG 日志会阻塞控制台程序, 必须要使这个条件为false, 不能执行这里
// LOG_EMERG 不仅是记录到日志, 还打印到正在运行的程序上, 阻塞了程序的执行. 不能用这种日志
i_mask |= LOG_MASK(LOG_EMERG);
}
if (b_ALERT) {
i_mask |= LOG_MASK(LOG_ALERT);
}
if (b_CRIT) {
i_mask |= LOG_MASK(LOG_CRIT);
}
if (b_ERR) {
i_mask |= LOG_MASK(LOG_ERR);
}
if (b_WARNING) {
i_mask |= LOG_MASK(LOG_WARNING);
}
if (b_NOTICE) {
i_mask |= LOG_MASK(LOG_NOTICE);
}
if (b_INFO) {
i_mask |= LOG_MASK(LOG_INFO);
}
if (b_DEBUG) {
i_mask |= LOG_MASK(LOG_DEBUG);
}
setlogmask(i_mask);
}
void close_syslog()
{
closelog();
}
} // namespace ns_syslog {
// @file my_syslog.h
// @brief syslog日志宏的定义
#include
#include
#include
#include
#include
#include
namespace ns_syslog {
typedef struct _tag_log_condition {
bool b_EMERG;
bool b_ALERT;
bool b_CRIT;
bool b_ERR;
bool b_WARNING;
bool b_NOTICE;
bool b_INFO;
bool b_DEBUG;
_tag_log_condition() {
b_EMERG = false;
b_ALERT = false;
b_CRIT = false;
b_ERR = false;
b_WARNING = false;
b_NOTICE = false;
b_INFO = false;
b_DEBUG = false;
}
} TAG_LOG_CONDITION;
extern TAG_LOG_CONDITION g_log_condition;
// ----------------------------------------------------------------------------
// syslog macro
// ----------------------------------------------------------------------------
#define MYLOG_EMERG(fmt, ...) \
if (ns_syslog::g_log_condition.b_EMERG) { \
syslog(LOG_EMERG, "[%s : %s.%d : %s()] : " fmt, "EMERG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_EM(fmt, ...) \
if (ns_syslog::g_log_condition.b_EMERG) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "EMERG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_ALERT(fmt, ...) \
if (ns_syslog::g_log_condition.b_ALERT) { \
syslog(LOG_ALERT, "[%s : %s.%d : %s()] : " fmt, "ALERT", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_A(fmt, ...) \
if (ns_syslog::g_log_condition.b_ALERT) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "ALERT", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_CRIT(fmt, ...) \
if (ns_syslog::g_log_condition.b_CRIT) { \
syslog(LOG_CRIT, "[%s : %s.%d : %s()] : " fmt, "CRIT", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_C(fmt, ...) \
if (ns_syslog::g_log_condition.b_CRIT) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "CRIT", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_ERR(fmt, ...) \
if (ns_syslog::g_log_condition.b_ERR) { \
syslog(LOG_ERR, "[%s : %s.%d : %s()] : " fmt, "ERR", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_E(fmt, ...) \
if (ns_syslog::g_log_condition.b_ERR) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "ERR", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_WARNING(fmt, ...) \
if (ns_syslog::g_log_condition.b_WARNING) { \
syslog(LOG_WARNING, "[%s : %s.%d : %s()] : " fmt, "WARNING", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_W(fmt, ...) \
if (ns_syslog::g_log_condition.b_WARNING) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "WARNING", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_NOTICE(fmt, ...) \
if (ns_syslog::g_log_condition.b_NOTICE) { \
syslog(LOG_NOTICE, "[%s : %s.%d : %s()] : " fmt, "NOTICE", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_N(fmt, ...) \
if (ns_syslog::g_log_condition.b_NOTICE) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "NOTICE", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_INFO(fmt, ...) \
if (ns_syslog::g_log_condition.b_INFO) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "INFO", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_I(fmt, ...) \
if (ns_syslog::g_log_condition.b_INFO) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "INFO", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_DEBUG(fmt, ...) \
if (ns_syslog::g_log_condition.b_DEBUG) { \
syslog(LOG_DEBUG, "[%s : %s.%d : %s()] : " fmt, "DEBUG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_D(fmt, ...) \
if (ns_syslog::g_log_condition.b_DEBUG) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "DEBUG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
void open_syslog(const char* pszLogOwner);
void set_log_level(
bool b_EMERG = false,
bool b_CRIT = false,
bool b_ALERT = false,
bool b_ERR = false,
bool b_WARNING = false,
bool b_NOTICE = false,
bool b_INFO = false,
bool b_DEBUG = false);
void close_syslog();
} // namespace ns_syslog {
// readme.txt 正则表达式从文件中读出来时, 带\n结尾, 如果直接regcomp,regcomp不报错, 但是regexec时, 本来匹配的正则表达式和目标字符串, 变成不匹配了
所以,如果正则表达式是从文件中读出时,要过滤一下\r\n
## @file test_regex_rule.dat
## match
#select * from abc where 1=1
.*\s+[0-9]\s*=\s*[0-9]
## not match
#carry
\b[Cc][Aa][Rr]\b
## match
#carry
\b[Cc][Aa][Rr]
## match
#rycar
[Cc][Aa][Rr]\b
## match
#Hello, someone name is Ben. do you hear me?
Ben
## match
#sales1.xls
sales.
## match
#wsales1.xls
sales.
## match
## regex中 '.'代表一个字符
#wsales1xls
sales.