Branch data Line data Source code
1 : : /* 2 : : ** Copyright (C) 2021 Sylvain Fargier 3 : : ** 4 : : ** This software is provided 'as-is', without any express or implied 5 : : ** warranty. In no event will the authors be held liable for any damages 6 : : ** arising from the use of this software. 7 : : ** 8 : : ** Permission is granted to anyone to use this software for any purpose, 9 : : ** including commercial applications, and to alter it and redistribute it 10 : : ** freely, subject to the following restrictions: 11 : : ** 12 : : ** 1. The origin of this software must not be misrepresented; you must not 13 : : ** claim that you wrote the original software. If you use this software 14 : : ** in a product, an acknowledgment in the product documentation would be 15 : : ** appreciated but is not required. 16 : : ** 2. Altered source versions must be plainly marked as such, and must not be 17 : : ** misrepresented as being the original software. 18 : : ** 3. This notice may not be removed or altered from any source distribution. 19 : : ** 20 : : ** Created on: 2021-10-18T18:44:27+02:00 21 : : ** Author: Sylvain Fargier <fargie_s> <fargier.sylvain@free.fr> 22 : : ** 23 : : */ 24 : : 25 : : #ifndef REGEX_HPP__ 26 : : #define REGEX_HPP__ 27 : : 28 : : #include <functional> 29 : : #include <iterator> 30 : : #include <string> 31 : : #include <type_traits> 32 : : #include <vector> 33 : : 34 : : #include <regex.h> 35 : : 36 : : namespace ccut { 37 : : 38 : : /** 39 : : * @brief posix regex wrapper 40 : : * @details useful with old libstdc++ that have buggy std::regex support 41 : : */ 42 : : class Regex 43 : : { 44 : : public: 45 : : typedef std::vector<std::string> MatchGroup; 46 : : 47 : : /** 48 : : * @param[in] re regex to compile 49 : : * @param[in] flags 50 : : * @throws std::invalid_parameter 51 : : */ 52 : : explicit Regex(const std::string &re, int flags = Flags::Extended); 53 : : ~Regex(); 54 : : Regex(const Regex &) = delete; 55 : : Regex &operator=(const Regex &) = delete; 56 : : 57 : : /** 58 : : * @brief execute regex 59 : : * @param[out] matches matching parts 60 : : * @details `MatchGroup's` capacity will be used to configure the match 61 : : * count, MaxMatchDefault will be used by default 62 : : * @return true if string matches 63 : : */ 64 : 3 : inline bool match(const std::string &str, MatchGroup &matches) const 65 : : { 66 : 3 : size_t offset = 0; 67 : 6 : return match(str, offset, matches); 68 : : } 69 : : 70 : : /** 71 : : * @brief execute regex 72 : : * @param[in] str string to run the regex on 73 : : * @param[in,out] offset matching start offset in str 74 : : * @param[out] matches matching parts 75 : : * @return true if string matches 76 : : * 77 : : * @details for simple single match, do use the signature without `offset` 78 : : * argument 79 : : * @details 80 : : * - if `offset` is non-zero, the beginning-of-line (^) will not match, 81 : : * - `offset` is set to the start of match in `str` 82 : : * - (end of match is `offset + matches[0].size()`) 83 : : */ 84 : : bool match(const std::string &str, 85 : : size_t &offset, 86 : : MatchGroup &matches) const; 87 : : 88 : : /** 89 : : * @brief execute regex to test for match 90 : : * @param[in] str string to run the regex on 91 : : * @return true if string matches 92 : : */ 93 : : bool search(const std::string &str) const; 94 : : 95 : : /** 96 : : * @brief replace matches in string 97 : : * 98 : : * @param[in] str string to run the regex on 99 : : * @param[in] fun replace function (`start` and `end` are str match offsets) 100 : : * @return std::string the string with replacements 101 : : * @example ``` 102 : : * Regex r("\\w+"); 103 : : * r.replace("this is a sentence", []() { return "blah"; }); 104 : : * // "blah blah blah blah" 105 : : * ``` 106 : : */ 107 : : std::string replace( 108 : : const std::string &str, 109 : : std::function<std::string(size_t start, size_t end)> fun) const; 110 : : 111 : : /** 112 : : * @brief convenience function (no arguments) 113 : : */ 114 : 6 : inline std::string replace(const std::string &str, 115 : : std::function<std::string()> fun) const 116 : : { 117 : : return replace(str, 118 : 19 : [&fun](size_t, size_t) -> std::string { return fun(); }); 119 : : } 120 : : 121 : : /** 122 : : * @brief convenience function (matching string argument) 123 : : */ 124 : 1 : inline std::string replace( 125 : : const std::string &str, 126 : : std::function<std::string(const std::string &sub)> fun) const 127 : : { 128 : : return replace(str, 129 : 4 : [&str, &fun](size_t start, size_t end) -> std::string { 130 : 8 : return fun(str.substr(start, end - start)); 131 : 1 : }); 132 : : } 133 : : 134 : : /** 135 : : * @brief advanced replace function 136 : : * 137 : : * @param[in] str string to run the regex on 138 : : * @param[in] fun replace function 139 : : * @param[in] maxMatch maximum match count (to reserve array) 140 : : * @return std::string the string with replacements 141 : : * @example ``` 142 : : * Regex r("[$][{](\\w+)[}]|[$](\\w+)"); 143 : : * r.replace("echo ${HOME}", [](Regex::MatchGroup &matches) -> std::string { 144 : : * const char *value = getenv(matches[1].c_str()); 145 : : * return value ? value : ""; 146 : : * }, 2); 147 : : * ``` 148 : : */ 149 : : std::string replace(const std::string &str, 150 : : std::function<std::string(const MatchGroup &matches)> fun, 151 : : size_t maxMatch = MaxMatchDefault) const; 152 : : 153 : : enum Flags 154 : : { 155 : : Extended = REG_EXTENDED, 156 : : ICase = REG_ICASE, 157 : : NewLine = REG_NEWLINE 158 : : }; 159 : : 160 : : static constexpr std::size_t MaxMatchDefault = 32; 161 : : 162 : : protected: 163 : : regex_t m_regex; 164 : : }; 165 : : 166 : : } /* namespace ccut */ 167 : : 168 : : #endif