正则表达式带回车符引起正则匹配失败

前言

在第三方正则工具中可以正常匹配的正则表达式和目标串,到了正式工程中,用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.

你可能感兴趣的:(正则表达式带回车符引起正则匹配失败)