我只是想从任何可能的字符串中创建一个正则表达式。

var usersString = "Hello?!*`~World()[]";
var expression = new RegExp(RegExp.escape(usersString))
var matches = "Hello".match(expression);

有内置的方法吗?如果不是,人们用什么?Ruby有RegExp.escape。我觉得我不需要写我自己的,必须有一些标准的东西。


当前回答

另一种(更安全的)方法是使用unicode转义格式\u{code}转义所有字符(而不仅仅是我们目前知道的一些特殊字符):

function escapeRegExp(text) {
    return Array.from(text)
           .map(char => `\\u{${char.charCodeAt(0).toString(16)}}`)
           .join('');
}

console.log(escapeRegExp('a.b')); // '\u{61}\u{2e}\u{62}'

请注意,你需要传递u标志来让这个方法工作:

var expression = new RegExp(escapeRegExp(usersString), 'u');

其他回答

这是长久之计。

function regExpEscapeFuture(literal_string) {
     return literal_string.replace(/[^A-Za-z0-9_]/g, '\\$&');
}

在https://github.com/benjamingr/RexExp.escape/上有一个RegExp.escape的ES7提议,在https://github.com/ljharb/regexp.escape上有一个polyfill可用。

一个基于被拒绝的ES提案的例子,包括检查属性是否已经存在,以防TC39改变他们的决定。


代码:

if (!Object.prototype.hasOwnProperty.call(RegExp, 'escape')) {
  RegExp.escape = function(string) {
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
    // https://github.com/benjamingr/RegExp.escape/issues/37
    return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
  };
}

代码简化:

Object.prototype.hasOwnProperty.call(RegExp,"escape")||(RegExp.escape=function(e){return e.replace(/[.*+\-?^${}()|[\]\\]/g,"\\$&")});

// ...
var assert = require('assert');
 
var str = 'hello. how are you?';
var regex = new RegExp(RegExp.escape(str), 'g');
assert.equal(String(regex), '/hello\. how are you\?/g');

还有一个npm模块在: https://www.npmjs.com/package/regexp.escape


你可以安装这个并这样使用它:


npm install regexp.escape

or

yarn add regexp.escape

var escape = require('regexp.escape');
var assert = require('assert');
 
var str = 'hello. how are you?';
var regex = new RegExp(escape(str), 'g');
assert.equal(String(regex), '/hello\. how are you\?/g');

在GitHub && NPM页面是如何使用shim/polyfill这个选项的描述。该逻辑基于返回regexp .escape || implementation;,其中实现包含上面使用的regexp。


NPM模块是一个额外的依赖项,但它也使外部贡献者更容易识别添加到代码中的逻辑部分。¯\()/¯

我借用了上面bobince的答案,创建了一个带标签的模板函数,用于创建RegExp,其中部分值被转义,部分值不被转义。

regex-escaped.js

RegExp.escape = text => text.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); RegExp.escaped = flags => function (regexStrings, ...escaped) { const source = regexStrings .map((s, i) => // escaped[i] will be undefined for the last value of s escaped[i] === undefined ? s : s + RegExp.escape(escaped[i].toString()) ) .join(''); return new RegExp(source, flags); }; function capitalizeFirstUserInputCaseInsensitiveMatch(text, userInput) { const [, before, match, after ] = RegExp.escaped('i')`^((?:(?!${userInput}).)*)(${userInput})?(.*)$`.exec(text); return `${before}${match.toUpperCase()}${after}`; } const text = 'hello (world)'; const userInput = 'lo (wor'; console.log(capitalizeFirstUserInputCaseInsensitiveMatch(text, userInput));

对于TypeScript的粉丝们…

global.d.ts

interface RegExpConstructor {
  /** Escapes a string so that it can be used as a literal within a `RegExp`. */
  escape(text: string): string;

  /**
   * Returns a tagged template function that creates `RegExp` with its template values escaped.
   *
   * This can be useful when using a `RegExp` to search with user input.
   *
   * @param flags The flags to apply to the `RegExp`.
   *
   * @example
   *
   * function capitalizeFirstUserInputCaseInsensitiveMatch(text: string, userInput: string) {
   *   const [, before, match, after ] =
   *     RegExp.escaped('i')`^((?:(?!${userInput}).)*)(${userInput})?(.*)$`.exec(text);
   *
   *   return `${before}${match.toUpperCase()}${after}`;
   * }
   */
  escaped(flags?: string): (regexStrings: TemplateStringsArray, ...escapedVals: Array<string | number>) => RegExp;
}
escapeRegExp = function(str) {
  if (str == null) return '';
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};

在jQuery UI的自动完成小部件(版本1.9.1)中,他们使用了一个略有不同的正则表达式(第6753行),下面是正则表达式与bobince方法的结合。

RegExp.escape = function( value ) {
     return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}