Ich brauchte dies, mit Escaping und Arbeiten in Safari (keine negativen Lookbehinds). Hier ist, was ich kam mit:
/**
* Quotes a string following the same rules as https://www.php.net/manual/function.preg-quote.php
*
* Sourced from https://locutus.io/php/preg_quote/
*
* @param {string} str String to quote.
* @param {?string} [delimiter] Delimiter to also quote.
* @returns {string} The quoted string.
*/
function regexQuote(str, delimiter) {
return (str + '').replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&');
}
/**
* Removes the diacritical marks from a string.
*
* Diacritical marks: {@link https://unicode-table.com/blocks/combining-diacritical-marks/}
*
* @param {string} str The string from which to strip the diacritical marks.
* @returns {string} Stripped string.
*/
function stripDiacriticalMarks(str) {
return unorm.nfkd(str).replaceAll(/[\u0300-\u036f]+/g, '');
}
/**
* Checks if the string `haystack` is like `needle`, `needle` can contain '%' and '_'
* characters which will behave as if used in a SQL LIKE condition. Character escaping
* is supported with '\'.
*
* @param {string} haystack The string to check if it is like `needle`.
* @param {string} needle The string used to check if `haystack` is like it.
* @param {boolean} [ai] Whether to check likeness in an accent-insensitive manner.
* @param {boolean} [ci] Whether to check likeness in a case-insensitive manner.
* @returns {boolean} True if `haystack` is like `needle`, otherwise, false.
*/
function strLike(haystack, needle, ai = true, ci = true) {
if (ai) {
haystack = stripDiacriticalMarks(haystack);
needle = stripDiacriticalMarks(needle);
}
needle = regexQuote(needle, '/');
let tokens = [];
for (let i = 0; i < needle.length; ) {
if (needle[i] === '\\') {
i += 2;
if (i < needle.length) {
if (needle[i] === '\\') {
tokens.push('\\\\');
i += 2;
} else {
tokens.push(needle[i]);
++i;
}
} else {
tokens.push('\\\\');
}
} else {
switch (needle[i]) {
case '_':
tokens.push('.')
break;
case '%':
tokens.push('.*')
break;
default:
tokens.push(needle[i]);
break;
}
++i;
}
}
return new RegExp(`^${tokens.join('')}$`, `u${ci ? 'i' : ''}`).test(haystack);
}
/**
* Escapes a string in a way that `strLike` will match it as-is, thus '%' and '_'
* would match a literal '%' and '_' respectively (and not behave as in a SQL LIKE
* condition).
*
* @param {string} str The string to escape.
* @returns {string} The escaped string.
*/
function escapeStrLike(str) {
let tokens = [];
for (let i = 0; i < str.length; i++) {
switch (str[i]) {
case '\\':
tokens.push('\\\\');
break;
case '%':
tokens.push('\\%')
break;
case '_':
tokens.push('\\_')
break;
default:
tokens.push(str[i]);
}
}
return tokens.join('');
}
Der obige Code ist abhängig von unorm und ist unicode-fähig, um Fälle wie diesen zu erkennen:
strLike('Hello ', 'Hello _'); // true
strLike('Hello ', '_e%o__'); // true
strLike('asdfas \\H\\\\%É\\l\\_\\l\\o asdfasf', '%' . escapeStrLike('\\h\\\\%e\\l\\_\\l\\o') . '%'); // true