/************************************************************************************************* * Regular expression * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Cabinet. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "kcregex.h" #include "myconf.h" #if _KC_PXREGEX extern "C" { #include } #else #include #endif namespace kyotocabinet { // common namespace /** * Regex internal. */ struct RegexCore { #if _KC_PXREGEX ::regex_t rbuf; bool alive; bool nosub; #else std::regex* rbuf; #endif }; /** * Default constructor. */ Regex::Regex() : opq_(NULL) { #if _KC_PXREGEX _assert_(true); RegexCore* core = new RegexCore; core->alive = false; core->nosub = false; opq_ = (void*)core; #else _assert_(true); RegexCore* core = new RegexCore; core->rbuf = NULL; opq_ = (void*)core; #endif } /** * Destructor. */ Regex::~Regex() { #if _KC_PXREGEX _assert_(true); RegexCore* core = (RegexCore*)opq_; if (core->alive) ::regfree(&core->rbuf); delete core; #else _assert_(true); RegexCore* core = (RegexCore*)opq_; delete core->rbuf; delete core; #endif } /** * Compile a string of regular expression. */ bool Regex::compile(const std::string& regex, uint32_t opts) { #if _KC_PXREGEX _assert_(true); RegexCore* core = (RegexCore*)opq_; if (core->alive) { ::regfree(&core->rbuf); core->alive = false; } int32_t cflags = REG_EXTENDED; if (opts & IGNCASE) cflags |= REG_ICASE; if ((opts & MATCHONLY) || regex.empty()) { cflags |= REG_NOSUB; core->nosub = true; } if (::regcomp(&core->rbuf, regex.c_str(), cflags) != 0) return false; core->alive = true; return true; #else _assert_(true); RegexCore* core = (RegexCore*)opq_; if (core->rbuf) { delete core->rbuf; core->rbuf = NULL; } int32_t cflags = std::regex::ECMAScript; if (opts & IGNCASE) cflags |= std::regex::icase; if ((opts & MATCHONLY) || regex.empty()) cflags |= std::regex::nosubs; try { core->rbuf = new std::regex(regex, (std::regex::flag_type)cflags); } catch (...) { core->rbuf = NULL; return false; } return true; #endif } /** * Check whether a string matches the regular expression. */ bool Regex::match(const std::string& str) { #if _KC_PXREGEX _assert_(true); RegexCore* core = (RegexCore*)opq_; if (!core->alive) return false; if (core->nosub) return ::regexec(&core->rbuf, str.c_str(), 0, NULL, 0) == 0; ::regmatch_t subs[1]; return ::regexec(&core->rbuf, str.c_str(), 1, subs, 0) == 0; #else _assert_(true); RegexCore* core = (RegexCore*)opq_; if (!core->rbuf) return false; std::smatch res; return std::regex_search(str, res, *core->rbuf); #endif } /** * Check whether a string matches the regular expression. */ std::string Regex::replace(const std::string& str, const std::string& alt) { #if _KC_PXREGEX _assert_(true); RegexCore* core = (RegexCore*)opq_; if (!core->alive || core->nosub) return str; regmatch_t subs[256]; if (::regexec(&core->rbuf, str.c_str(), sizeof(subs) / sizeof(*subs), subs, 0) != 0) return str; const char* sp = str.c_str(); std::string xstr; bool first = true; while (sp[0] != '\0' && ::regexec(&core->rbuf, sp, 10, subs, first ? 0 : REG_NOTBOL) == 0) { first = false; if (subs[0].rm_so == -1) break; xstr.append(sp, subs[0].rm_so); for (const char* rp = alt.c_str(); *rp != '\0'; rp++) { if (*rp == '$') { if (rp[1] >= '0' && rp[1] <= '9') { int32_t num = rp[1] - '0'; if (subs[num].rm_so != -1 && subs[num].rm_eo != -1) xstr.append(sp + subs[num].rm_so, subs[num].rm_eo - subs[num].rm_so); ++rp; } else if (rp[1] == '&') { xstr.append(sp + subs[0].rm_so, subs[0].rm_eo - subs[0].rm_so); ++rp; } else if (rp[1] != '\0') { xstr.append(++rp, 1); } } else { xstr.append(rp, 1); } } sp += subs[0].rm_eo; if (subs[0].rm_eo < 1) break; } xstr.append(sp); return xstr; #else _assert_(true); RegexCore* core = (RegexCore*)opq_; if (!core->rbuf) return str; return std::regex_replace(str, *core->rbuf, alt); #endif } } // common namespace // END OF FILE