如何LIKE
在 JavaScript 中模拟 SQL 关键字?
对于那些不知道是什么的人LIKE
来说,这是一个非常简单的正则表达式,它只支持通配符%
,它匹配 0 个或多个字符,并且_
只匹配一个字符。
但是,不仅可以执行以下操作:
var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null;
...因为该模式可能包含点、星和任何其他特殊的正则表达式字符。
如何LIKE
在 JavaScript 中模拟 SQL 关键字?
对于那些不知道是什么的人LIKE
来说,这是一个非常简单的正则表达式,它只支持通配符%
,它匹配 0 个或多个字符,并且_
只匹配一个字符。
但是,不仅可以执行以下操作:
var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null;
...因为该模式可能包含点、星和任何其他特殊的正则表达式字符。
只要您首先转义模式中的正则表达式字符,您所拥有的就会起作用。以下是Simon Willison 博客中的一个示例:
RegExp.escape = function(text) {
if (!arguments.callee.sRE) {
var specials = [
'/', '.', '*', '+', '?', '|',
'(', ')', '[', ']', '{', '}', '\\'
];
arguments.callee.sRE = new RegExp(
'(\\' + specials.join('|\\') + ')', 'g'
);
}
return text.replace(arguments.callee.sRE, '\\$1');
}
然后,您可以将代码实现为:
likeExpr = RegExp.escape(likeExpr);
var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null;
我正在寻找相同问题的答案,并在阅读了 Kip 的回复后提出了这个问题:
String.prototype.like = function(search) {
if (typeof search !== 'string' || this === null) {return false; }
// Remove special chars
search = search.replace(new RegExp("([\\.\\\\\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\-])", "g"), "\\$1");
// Replace % and _ with equivalent regex
search = search.replace(/%/g, '.*').replace(/_/g, '.');
// Check matches
return RegExp('^' + search + '$', 'gi').test(this);
}
然后您可以按如下方式使用它(注意它忽略了大写/小写):
var url = 'http://www.mydomain.com/page1.aspx';
console.log(url.like('%mydomain.com/page_.asp%')); // true
注意 29/11/2013:RegExp.test()
根据下面的 Lucios 评论更新了性能改进。
这是我使用的一个函数,基于PHP 的 preg_quote 函数:
function regex_quote(str) {
return str.replace(new RegExp("([\\.\\\\\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\-])", "g"), "\\$1");
}
所以你的行现在是:
var match = new RegEx(regex_quote(likeExpr).replace("%", ".*").replace("_", ".")).exec(str) != null;
一个老问题,但这里实际上没有好的答案。TSQL LIKE 表达式可以包含方括号转义部分,这些部分已经是几乎有效的正则表达式并允许匹配%
和_
。例如:
'75%' LIKE '75[%]'
'[foo]' LIKE '[[]foo]' -- ugh
这是我将 LIKE 表达式转换为 RegExp 的函数。输入分为方括号和非方括号部分。方括号部分只需要反斜杠转义,非方括号部分完全转义,而%
and_
指令转换为正则表达式。
const likeRegExp = (expression, caseSensitive = false) =>
new RegExp(`^${
expression.split(/(\[.+?\])/g)
.map((s, i) => i % 2 ?
s.replace(/\\/g, '\\\\') :
s.replace(/[-\/\\^$*+?.()|[\]{}%_]/g, m => {
switch(m) {
case '%': return '.*';
case '_': return '.';
default: return `\\${m}`;
}
})
).join('')
}$`, caseSensitive ? '' : 'i');
如果要使用正则表达式,可以将字符串的每个字符括在方括号中。那么你只有几个字符可以逃脱。
但更好的选择可能是截断目标字符串,以便长度与您的搜索字符串匹配并检查是否相等。
在 Chris Van Opstal 的回答中,您应该使用 replaceAll 而不是 replace 替换所有出现的“%”和“_”。参考如何做 replaceAll -这里
约翰尼最近来到这里,但这对我有用,我将它用于我的水疗页面,以避免某些页面在默认页面之后显示结果:
function like(haystack,needle){
needle = needle.split(',');
var str = haystack.toLowerCase();
var n = -1;
for(var i=0;i<needle.length;i++){
n = str.search(needle[i]);
if(n > -1){
return n;
}
}
return n;
}
用法是 - 在这里我不想在工具、联系人或主页上显示任何结果 - results() 是一个我不在这里显示的函数:
var n = like($data,'tools,contact,home');
//~ alert(n);
if(n < 0){// does not match anything in the above string
results($data);
}
我想要一些也可以处理转义通配符%
和_
使用\%
and的东西\_
。
这是我使用负面后视的解决方案:
// escapes RegExp special characters
const escapePattern = s => s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
// converts ILIKE pattern to a RegExp object
const ilikeToRegExp = pattern =>
new RegExp(
`^${escapePattern(pattern)}$`
// convert ILIKE wildcards, don't match escaped
.replace(/(?<![\\])%/g, '.*')
.replace(/(?<![\\])_/g, '.')
// replace ILIKE escapes
.replace(/\\%/g, '%')
.replace(/\\_/g, '_'),
'i'
);
用法:
ilikeToRegExp('%eLlo WoR%').test('hello world')
// true
ilikeToRegExp('ello wor').test('hello world')
// false
ilikeToRegExp('%90\%%').test('...90%...')
// true
我需要这个,在 Safari 中转义和工作(没有负面的后视)。这是我想出的:
/**
* 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('');
}
上面的代码依赖于unorm,并且可以识别 unicode 以捕获以下情况:
strLike('Hello ', 'Hello _'); // true
strLike('Hello ', '_e%o__'); // true
strLike('asdfas \\H\\\\%É\\l\\_\\l\\o asdfasf', '%' . escapeStrLike('\\h\\\\%e\\l\\_\\l\\o') . '%'); // true
我最终根据这里的一些答案编写了一个对我来说效果很好的函数。我需要一些可以保留“startswith%”和“%endswith”语法的东西,并且不返回空搜索字符串的匹配项。
function sqlLIKE(target, likeExp) {
let regex = likeExp
.replaceAll(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1')
.replaceAll("%", ".*")
.replaceAll("_", ".");
if (likeExp.charAt(0) !== '%' || !likeExp.includes('%')) regex = `^${regex}`;
if (likeExp.charAt(likeExp.length - 1) !== '%' || !likeExp.includes('%')) regex = `${regex}$`;
return new RegExp(regex).exec(target) !== null;
}