9std::string basename(
const std::string& path) {
10 size_t idx = path.find_last_of(
"/\\");
11 if (idx == std::string::npos) {
13 }
else if (idx == path.length() - 1) {
14 return basename(path.substr(0, path.length() - 1));
16 return path.substr(idx + 1);
20int strcmp_custom(
const std::string& a,
const std::string& b) {
30int strArrCmp(
const std::vector<std::string>* a,
const std::vector<std::string>* b) {
31 if (a ==
nullptr && b ==
nullptr) {
40 size_t len1 = a->size();
41 size_t len2 = b->size();
43 for (
size_t i = 0; i < len1; i++) {
44 int res = strcmp_custom((*a)[i], (*b)[i]);
51 return static_cast<int>(len1) -
static_cast<int>(len2);
54bool isValidHexColor(
const std::string& hex) {
55 std::regex pattern1(
"^#[0-9a-fA-F]{6}$");
56 std::regex pattern2(
"^#[0-9a-fA-F]{8}$");
57 std::regex pattern3(
"^#[0-9a-fA-F]{3}$");
58 std::regex pattern4(
"^#[0-9a-fA-F]{4}$");
60 return std::regex_match(hex, pattern1) ||
61 std::regex_match(hex, pattern2) ||
62 std::regex_match(hex, pattern3) ||
63 std::regex_match(hex, pattern4);
66std::string escapeRegExpCharacters(
const std::string& value) {
68 result.reserve(value.length() * 2);
69 for (
char c : value) {
70 if (c ==
'-' || c ==
'\\' || c ==
'{' || c ==
'}' || c ==
'*' ||
71 c ==
'+' || c ==
'?' || c ==
'|' || c ==
'^' || c ==
'$' ||
72 c ==
'.' || c ==
',' || c ==
'[' || c ==
']' || c ==
'(' ||
73 c ==
')' || c ==
'#' || std::isspace(c)) {
82static std::regex* CONTAINS_RTL =
nullptr;
84static std::regex makeContainsRtl() {
87 "(?:[\u05BE\u05C0\u05C3\u05C6\u05D0-\u05F4\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F"
88 "\u0671-\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u0710\u0712-\u072F\u074D-\u07A5\u07B1-\u07EA"
89 "\u07F4\u07F5\u07FA\u07FE-\u0815\u081A\u0824\u0828\u0830-\u0858\u085E-\u088E\u08A0-\u08C9"
90 "\u200F\uFB1D\uFB1F-\uFB28\uFB2A-\uFD3D\uFD50-\uFDC7\uFDF0-\uFDFC\uFE70-\uFEFC])",
91 std::regex_constants::ECMAScript
95bool containsRTL(
const std::string& str) {
96 if (CONTAINS_RTL ==
nullptr) {
97 CONTAINS_RTL =
new std::regex(makeContainsRtl());
99 return std::regex_search(str, *CONTAINS_RTL);
102double performanceNow() {
103 auto now = std::chrono::high_resolution_clock::now();
104 auto duration = now.time_since_epoch();
105 return std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
110static std::regex CAPTURING_REGEX_SOURCE(
"\\$(\\d+)|\\$\\{(\\d+):\\/(downcase|upcase)\\}");
112RegexSource::RegexSource(
const std::string& regExpSource, RuleId ruleId_)
113 : source(regExpSource), ruleId(ruleId_), hasAnchor(false), hasBackReferences(false) {
116 if (regExpSource.find(
"\\A") != std::string::npos ||
117 regExpSource.find(
"\\G") != std::string::npos) {
122 std::regex backRefPattern(
"\\\\(\\d+)");
123 hasBackReferences = std::regex_search(regExpSource, backRefPattern);
131bool RegexSource::hasCaptures(
const std::string* regexSource) {
132 if (regexSource ==
nullptr) {
135 return std::regex_search(*regexSource, CAPTURING_REGEX_SOURCE);
138std::string RegexSource::replaceCaptures(
const std::string& regexSource,
139 const std::string& captureSource,
140 const std::vector<IOnigCaptureIndex>& captureIndices) {
143 std::string::const_iterator searchStart(regexSource.cbegin());
145 while (std::regex_search(searchStart, regexSource.cend(), match, CAPTURING_REGEX_SOURCE)) {
146 result += match.prefix();
148 std::string indexStr = match[1].matched ? match[1].str() : match[2].str();
149 std::string command = match[3].matched ? match[3].str() :
"";
151 int index = std::stoi(indexStr);
153 if (index <
static_cast<int>(captureIndices.size())) {
154 const IOnigCaptureIndex& capture = captureIndices[index];
155 if (capture.length > 0) {
156 std::string captureText = captureSource.substr(capture.start, capture.length);
159 while (!captureText.empty() && captureText[0] ==
'.') {
160 captureText = captureText.substr(1);
163 if (command ==
"downcase") {
164 std::transform(captureText.begin(), captureText.end(), captureText.begin(), ::tolower);
165 }
else if (command ==
"upcase") {
166 std::transform(captureText.begin(), captureText.end(), captureText.begin(), ::toupper);
169 result += captureText;
171 result += match.str();
174 result += match.str();
177 searchStart = match.suffix().first;
180 result += std::string(searchStart, regexSource.cend());
184std::string RegexSource::resolveBackReferences(
const std::string& lineText,
185 const std::vector<IOnigCaptureIndex>& captureIndices) {
186 std::regex backRefPattern(
"\\\\(\\d+)");
189 std::string::const_iterator searchStart(source.cbegin());
191 while (std::regex_search(searchStart, source.cend(), match, backRefPattern)) {
192 result += match.prefix();
194 int index = std::stoi(match[1].str());
196 if (index <
static_cast<int>(captureIndices.size())) {
197 const IOnigCaptureIndex& capture = captureIndices[index];
198 if (capture.length > 0) {
199 std::string captureText = lineText.substr(capture.start, capture.length);
200 result += escapeRegExpCharacters(captureText);
203 result += match.str();
206 searchStart = match.suffix().first;
209 result += std::string(searchStart, source.cend());
213void RegexSource::buildAnchorCache() {
221 std::string A0_G0_result;
222 std::string A0_G1_result;
223 std::string A1_G0_result;
224 std::string A1_G1_result;
226 A0_G0_result.reserve(source.length());
227 A0_G1_result.reserve(source.length());
228 A1_G0_result.reserve(source.length());
229 A1_G1_result.reserve(source.length());
231 for (
size_t i = 0; i < source.length(); i++) {
240 if (ch ==
'\\' && i + 1 < source.length()) {
241 char nextCh = source[i + 1];
247 A0_G0_result +=
"\uFFFF";
248 A0_G1_result +=
"\uFFFF";
251 }
else if (nextCh ==
'G') {
253 A0_G0_result +=
"\uFFFF";
255 A1_G0_result +=
"\uFFFF";
259 A0_G0_result += nextCh;
260 A0_G1_result += nextCh;
261 A1_G0_result += nextCh;
262 A1_G1_result += nextCh;
267 anchorCache_A0_G0 = A0_G0_result;
268 anchorCache_A0_G1 = A0_G1_result;
269 anchorCache_A1_G0 = A1_G0_result;
270 anchorCache_A1_G1 = A1_G1_result;
273std::string RegexSource::resolveAnchors(
bool allowA,
bool allowG)
const {
280 return anchorCache_A1_G1;
282 return anchorCache_A1_G0;
286 return anchorCache_A0_G1;
288 return anchorCache_A0_G0;
293RegexSource* RegexSource::clone()
const {
294 return new RegexSource(source, ruleId);