14 Stimmen

SQL LIKE in JavaScript emulieren

Wie kann ich das SQL-Schlüsselwort emulieren? LIKE in JavaScript?

Für diejenigen unter Ihnen, die nicht wissen, was LIKE ist eine sehr einfache Regex, die nur die Wildcards unterstützt % der auf 0 oder mehr Zeichen passt, und _ die genau einem Zeichen entspricht.

Es ist jedoch nicht nur möglich, so etwas zu tun:

var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null;

...weil das Muster Punkte, Sterne und andere spezielle Regex-Zeichen enthalten kann.

1voto

Rafi Punkte 707

Ich wollte etwas, das auch mit dem Escapen der Platzhalter umgehen kann % y _ mit \% y \_ .

Hier ist meine Lösung mit negativem Lookbehind:

// 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'
  );

Verwendung:

ilikeToRegExp('%eLlo WoR%').test('hello world')  
// true

ilikeToRegExp('ello wor').test('hello world')  
// false

ilikeToRegExp('%90\%%').test('...90%...') 
// true

0voto

Pramod Shivale Punkte 61

In der Antwort von Chris Van Opstal sollten Sie replaceAll anstelle von replace verwenden, um alle Vorkommen von '%' und '_' zu ersetzen. Verweis darauf, wie man replaceAll verwendet - aquí

0voto

richardwhitney Punkte 486

Johnny kommt erst seit kurzem hierher, aber das funktioniert für mich. Ich verwende es für meine Spa-Seiten, um zu vermeiden, dass bestimmte Seiten nach der Standardseite Ergebnisse anzeigen:

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;
}

Verwendung ist - hier möchte ich keine Ergebnisse auf den Seiten tools, contact oder home anzeigen - results() ist eine Funktion, die ich hier nicht zeige:

var n = like($data,'tools,contact,home');
//~ alert(n);
if(n < 0){// does not match anything in the above string
  results($data);
}

0voto

mishamosher Punkte 968

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

0voto

pigeontoe Punkte 416

Ich habe schließlich eine Funktion auf der Grundlage einiger Antworten hier geschrieben, die für mich ziemlich gut funktioniert hat. Ich brauchte etwas, das die Syntax "startswith%" und "%endswith" beibehält und bei einer leeren Suchzeichenfolge keine Treffer liefert.

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;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X