From 780b28bfb42faa6496f8ddb9b02b6c65609e03fd Mon Sep 17 00:00:00 2001 From: Joshua Poon <93095025+JoshuaPoon1@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:43:39 -0500 Subject: [PATCH 1/2] Update 15utility.js to improve readability. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Edited utils.glob and utils.like to improve readability. Proved comments to help reader traverse through code. Also rename: und ----> undefinedOrValue n2u ——> nanToUndefined --- src/15utility.js | 156 +++++++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 65 deletions(-) diff --git a/src/15utility.js b/src/15utility.js index 4c0ec4770c..5f95fef506 100755 --- a/src/15utility.js +++ b/src/15utility.js @@ -1,4 +1,4 @@ -/*jshint unused:false*/ + /*jshint unused:false*/ /* Utilities for Alasql.js @@ -25,7 +25,7 @@ var utils = (alasql.utils = {}); NaN => undefined */ -function n2u(s) { +function nanToUndefined(s) { //rename for clarity. return '(y=' + s + ',y===y?y:undefined)'; } @@ -41,7 +41,7 @@ function n2u(s) { NaN,a => undefined */ -function und(s, r) { +function undefinedOrValue(s, r) { //rename for clarity return '(y=' + s + ',typeof y=="undefined"?undefined:' + r + ')'; } @@ -1171,76 +1171,102 @@ var domEmptyChildren = (utils.domEmptyChildren = function (container) { @parameter {string} escape Escape character (optional) @return {boolean} If value LIKE pattern ESCAPE escape */ + +/* * Tests if a given value matches a pattern with optional escape character. + * Supports SQL-like syntax with % and _ as wildcards and custom escape character. + */ var patternCache = {}; -var like = (utils.like = function (pattern, value, escape) { +var like = (utils.like = function (pattern, value, escape = '') { if (!patternCache[pattern]) { - // Verify escape character - if (!escape) escape = ''; - - var i = 0; - var s = '^'; - - while (i < pattern.length) { - var c = pattern[i], - c1 = ''; - if (i < pattern.length - 1) c1 = pattern[i + 1]; - - if (c === escape) { - s += '\\' + c1; - i++; - } else if (c === '[' && c1 === '^') { - s += '[^'; - i++; - } else if (c === '[' || c === ']') { - s += c; - } else if (c === '%') { - s += '[\\s\\S]*'; - } else if (c === '_') { - s += '.'; - } else if ('/.*+?|(){}'.indexOf(c) > -1) { - s += '\\' + c; - } else { - s += c; - } - i++; - } - s += '$'; - // if(value == undefined) return false; - //console.log(s,value,(value||'').search(RegExp(s))>-1); - patternCache[pattern] = RegExp(s, 'i'); - } - return ('' + (value ?? '')).search(patternCache[pattern]) > -1; -}); + var regexStr = '^'; // Start regex pattern to match from the beginning. + var i = 0; // Index for traversing the pattern string. + + while (i < pattern.length) { + var currentChar = pattern[i]; + var nextChar = i < pattern.length - 1 ? pattern[i + 1] : ''; + + // Handle escape character. + if (currentChar === escape) { + regexStr += '\\' + nextChar; + i++; // Skip next character as it's escaped. + } + // Handle negation within character classes. + else if (currentChar === '[' && nextChar === '^') { + regexStr += '[^'; + i++; // Include '^' as part of the set. + } + // Directly append square brackets. + else if (currentChar === '[' || currentChar === ']') { + regexStr += currentChar; + } + // Replace '%' with regex to match any character sequence. + else if (currentChar === '%') { + regexStr += '[\\s\\S]*'; + } + // Replace '_' with regex to match any single character. + else if (currentChar === '_') { + regexStr += '.'; + } + // Escape special regex characters. + else if ('/.*+?|(){}'.indexOf(currentChar) > -1) { + regexStr += '\\' + currentChar; + } + // Append literal characters. + else { + regexStr += currentChar; + } + i++; + } + + regexStr += '$'; // End regex pattern to match until the end. + // Compile and cache the regex pattern for future use. + patternCache[pattern] = RegExp(regexStr, 'i'); + } + + // Convert value to string (handling null/undefined) and test against compiled pattern. + return ('' + (value ?? '')).search(patternCache[pattern]) > -1; + }); +/** + * Tests if a given value matches a glob pattern. + * The function supports '*', '?' as wildcards where '*' matches any sequence of characters, + * and '?' matches any single character. Square brackets can be used for character sets and ranges. + * + * @param {string} value - The string value to test against the glob pattern. + * @param {string} pattern - The glob pattern to match the value against. + * @returns {boolean} - True if the value matches the pattern, false otherwise. + */ utils.glob = function (value, pattern) { - var i = 0; - var s = '^'; - - while (i < pattern.length) { - var c = pattern[i], - c1 = ''; - if (i < pattern.length - 1) c1 = pattern[i + 1]; - - if (c === '[' && c1 === '^') { - s += '[^'; - i++; - } else if (c === '[' || c === ']') { - s += c; - } else if (c === '*') { - s += '.*'; - } else if (c === '?') { - s += '.'; - } else if ('/.*+?|(){}'.indexOf(c) > -1) { - s += '\\' + c; - } else { - s += c; + var currentIndex = 0; // Index for traversing the pattern string. + var regexPattern = '^'; // Start regex pattern to match from the beginning. + + while (currentIndex < pattern.length) { + var currentChar = pattern[currentIndex]; + var nextChar = currentIndex < pattern.length - 1 ? pattern[currentIndex + 1] : ''; + + // Handle character sets and negation within them. + if (currentChar === '[' && nextChar === '^') { + regexPattern += '[^'; + currentIndex++; // Include '^' as part of the set. + } else if (currentChar === '[' || currentChar === ']') { // Directly append square brackets. + regexPattern += currentChar; + } else if (currentChar === '*') { // Replace '*' with regex to match any character sequence. + regexPattern += '.*'; + } else if (currentChar === '?') { // Replace '?' with regex to match any single character. + regexPattern += '.'; + } else if ('/.*+?|(){}'.indexOf(currentChar) > -1) {// Escape special regex characters. + regexPattern += '\\' + currentChar; + } else { // Append literal characters. + regexPattern += currentChar; } - i++; + currentIndex++; } - s += '$'; - return ('' + (value || '')).toUpperCase().search(RegExp(s.toUpperCase())) > -1; + regexPattern += '$'; // End regex pattern to match until the end. + + // Convert value to uppercase, compile the regex pattern in uppercase to perform a case-insensitive match. + return ('' + (value || '')).toUpperCase().search(RegExp(regexPattern.toUpperCase())) > -1; }; /** From 038373637958b1d52eafde50318338acd051fbde Mon Sep 17 00:00:00 2001 From: Mathias Wulff Date: Thu, 11 Jul 2024 23:06:32 +0200 Subject: [PATCH 2/2] Update 15utility.js --- src/15utility.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/15utility.js b/src/15utility.js index 5f95fef506..a01833e7c0 100755 --- a/src/15utility.js +++ b/src/15utility.js @@ -1,4 +1,4 @@ - /*jshint unused:false*/ +/*jshint unused:false*/ /* Utilities for Alasql.js