在JavaScript中模拟SQL LIKE操作
在JavaScript中模拟SQL的LIKE语法是一个经常被问到但却没有很好的答案的问题。TSQL的LIKE表达式可以包含方括号转义的部分,这些部分几乎是有效的正则表达式,并且允许匹配%
和_
。例如:
'75%' LIKE '75[%]' '[foo]' LIKE '[[]foo]' -- ugh
下面是我的一个函数,用于将LIKE表达式转换为正则表达式。输入被分成方括号和非方括号的部分。方括号的部分只需要进行反斜杠转义,而非方括号的部分则完全转义,同时%
和_
指令被转换为正则表达式。
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');
任何寻找将SQL LIKE语法转换为JavaScript正则表达式的解决方案的人,这是一个可行的方法。它将生成一个可以使用.test()等方法进行匹配的正则表达式。
在JavaScript中模拟SQL的LIKE语句的问题是因为JavaScript本身没有提供类似于SQL的LIKE语句的功能。解决方法是通过自定义字符串原型的like方法来实现类似的功能。
以下是解决方法的代码:
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
该解决方法在2013年11月29日进行了更新,根据Lucios的评论,使用了RegExp.test()方法来提高性能。
有人提出了一个问题,为什么不使用this.test(...)而是使用!!this.match(...),后面的回答指出this.test(...)是针对正则表达式实例的,而不是字符串对象。
然后又有人提出了一个改进的建议,使用return new RegExp(...).test(this)来替代将数组或null转换为布尔值的双重否定。
最后,有人赞同了这个解决方案,并更新了代码以实现提出的改进。
在JavaScript中模拟SQL LIKE的问题是由于需要在JavaScript中实现类似SQL LIKE的功能。解决方法是使用正则表达式来模拟LIKE操作符。
问题的解决方法如下:
首先,需要对模式中的正则表达式特殊字符进行转义。可以使用以下代码来实现转义:
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'); }
然后,可以使用以下代码来实现模拟LIKE操作符:
likeExpr = RegExp.escape(likeExpr); var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null;
另外,可以使用以下代码来实现更加可重用的模拟LIKE操作符:
RegExp.like = function (text) { return new RegExp("^"+(RegExp.escape(text).replace(/%/g, ".*").replace(/_/g, "."))+"$"); }
上述代码中的Regex.escape
实现方式有些冗余。首先,arguments.callee
的使用会阻碍一些现代浏览器的优化,并且在ES5-strict中已被弃用,所以在可能的情况下最好避免使用它。其次,对字符进行转义是不必要的,可以将它们放在字符类中。以下是在Prototype.js中使用的更小(并且可能更快)的版本:RegExp.escape = function(str) { return str.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); };
在SQL中,LIKE 'examp%'
可以匹配"example"但无法匹配"an example"(参考w3schools.com/SQL/sql_like.asp),然而上述答案可以匹配两者。对于第二行的改进可以是:var match = new RegEx("^"+likeExpr.replace("%", ".*").replace("_", ".")+"$").exec(str) != null;