Есть ли функция RegExp.escape в Javascript?

353

Я просто хочу создать регулярное выражение из любой возможной строки.

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

Есть ли встроенный метод для этого? Если нет, что люди используют? Ruby имеет RegExp.escape. Я не чувствую, что мне нужно написать свое, там должно быть что-то стандартное. Спасибо!

Теги:

13 ответов

416
Лучший ответ

Недопустимая функция, связанная выше. Он не может выйти из ^ или $ (начало и конец строки) или -, которое в группе символов используется для диапазонов.

Используйте эту функцию:

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

Хотя на первый взгляд это может показаться излишним, экранирование - (а также ^) делает функцию, подходящую для экранирования символов, вставляться в класс символов, а также тело регулярного выражения.

Escaping / делает функцию, подходящую для экранирующих символов, использоваться в литературе JS regex для последующего eval.

Поскольку нет недостатков, чтобы избежать любого из них, имеет смысл убежать, чтобы охватить более широкие варианты использования.

И да, это разочаровывает неудача, что это не часть стандартного JavaScript.

  • 3
    Что делает $& делать?
  • 4
    @spinningarrow: представляет всю совпадающую строку, как «группа 0» во многих других системах регулярных выражений. доктор
Показать ещё 31 комментарий
69

Для тех, кто использует lodash, с версии v3.0.0, функция _. escapeRegExp встроена:

_.escapeRegExp('[lodash](https://lodash.com/)');
// → '\[lodash\]\(https:\/\/lodash\.com\/\)'

И если вам не нужна полная библиотека lodash, вам может потребоваться только эта функция!

  • 4
    есть даже пакет npm только этого! npmjs.com/package/lodash.escaperegexp
  • 0
    Имейте в виду, что функция escapeRegExp lodash также добавляет \ x3 в начало строки, не очень понятно почему.
Показать ещё 4 комментария
29

Большинство выражений здесь описывают отдельные конкретные варианты использования.

Это хорошо, но я предпочитаю подход "всегда работает".

function regExpEscape(literal_string) {
    return literal_string.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
}

Это будет "полностью избежать" буквальной строки для любого из следующих применений в регулярных выражениях:

  • Вставка в регулярное выражение. Например. new RegExp(regExpEscape(str))
  • Вставка в класс символов. Например. new RegExp('[' + regExpEscape(str) + ']')
  • Вставка в спецификатор целых чисел. Например. new RegExp('x{1,' + regExpEscape(str) + '}')
  • Выполнение в механизмах регулярного выражения без JavaScript.

Специальные символы:

  • -: Создает диапазон символов в классе символов.
  • [/]: Запускает/завершает класс символов.
  • {/}: Запускает/завершает спецификатор нумерации.
  • (/): Запускает/завершает группу.
  • */+/?: указывает тип повторения.
  • .: соответствует любому символу.
  • \: стирает символы и запускает объекты.
  • ^: Задает начало зоны соответствия и отменяет соответствие в классе символов.
  • $: Задает конец зоны соответствия.
  • |: Указывает чередование.
  • #: указывает комментарий в режиме свободного интервала.
  • \s: Игнорируется в режиме свободного интервала.
  • ,: разделяет значения в спецификаторе нумерации.
  • /: начинает или завершает выражение.
  • :: Завершает специальные типы групп и часть классов символов в стиле Perl.
  • !: Отменяет группу нулевой ширины.
  • </=: Часть спецификаций группы нулевой ширины.

Примечания:

  • / не является строго необходимым в любом вкусе регулярного выражения. Тем не менее, он защищает, если кто-то (дрожь) делает eval("/" + pattern + "/");.
  • , гарантирует, что если строка должна быть целым числом в числовом спецификаторе, она будет корректно вызывать ошибку компиляции RegExp вместо того, чтобы молча выполнять компиляцию.
  • # и \s не нужно бежать в JavaScript, но делать это во многих других вариантах. Они сбегают здесь, если регулярное выражение будет передано в другую программу.

Если вам также необходимо проверять будущее регулярное выражение от возможных дополнений к возможностям JavaScript-регекса JavaScript, я рекомендую использовать более параноидальный:

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

Эта функция пропускает каждый символ, за исключением тех, которые явно гарантированно не используются для синтаксиса в будущих ароматах регулярных выражений.


Для истинной санитарии рассмотрите этот краевой случай:

var s = '';
new RegExp('(choice1|choice2|' + regExpEscape(s) + ')');

Это должно хорошо компилироваться в JavaScript, но не будет в некоторых других вариантах. Если намереваться передать другой вкус, нулевой случай s === '' должен быть независимо проверен, например:

var s = '';
new RegExp('(choice1|choice2' + (s ? '|' + regExpEscape(s) : '') + ')');
  • 1
    / Не нужно экранировать в [...] символьном классе.
  • 1
    Большинству из них не нужно избегать. «Создает диапазон символов в классе символов» - вы никогда не находитесь в классе символов внутри строки. «Определяет комментарий в режиме свободного пространства, игнорируется в режиме свободного пространства» - не поддерживается в javascript. «Разделяет значения в спецификаторе нумерации» - вы никогда не входите в спецификатор нумерации внутри строки. Также вы не можете написать произвольный текст внутри спецификации именования. «Начинает или заканчивает выражение» - не нужно убегать. Eval - это не тот случай, так как он потребует гораздо большего ухода. [будет продолжено в следующем комментарии]
Показать ещё 4 комментария
18

В виджетах jQueryUI autocomplete (версия 1.9.1) они используют немного другое регулярное выражение (строка 6753), здесь это регулярное выражение в сочетании с подходом @bobince.

RegExp.escape = function( value ) {
     return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
  • 4
    Единственное отличие состоит в том , что они убегают , (который не метасимволом) и # и пробелы , которые только материя в режиме свободного расстояния (который не поддерживается JavaScript). Тем не менее, они понимают это правильно, чтобы не избежать косой черты.
  • 18
    Если вы хотите повторно использовать реализацию пользовательского интерфейса jquery, а не вставлять код локально, используйте $.ui.autocomplete.escapeRegex(myString) .
Показать ещё 2 комментария
14

Руководство по регулярным выражениям для Mozilla Developer Network предоставляет следующую функцию:

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
  • 0
    Почему они избегают = ? AFAIK, это было бы полезно для регулярных выражений в Perl ( ?= ), Но если вы избежите ? ты в порядке.
  • 0
    @DanDascalescu Ты прав. Страница MDN была обновлена и = больше не включена.
8

Ничто не должно препятствовать простому экранированию каждого не-буквенно-цифрового символа:

usersString.replace(/(?=\W)/g, '\\');

Вы теряете определенную степень удобочитаемости при выполнении re.toString(), но вы выигрываете большую простоту (и безопасность).

В соответствии с ECMA-262, с одной стороны, регулярные выражения "синтаксические символы" всегда не являются алфавитно-цифровыми, так что результат является безопасным, а специальные escape-последовательности (\d, \w, \n) всегда являются буквенно-цифровыми, так что не будут выдаваться ложные контрольные экраны.

  • 0
    Просто и эффективно. Мне это нравится намного лучше, чем принятый ответ. Для (действительно) старых браузеров .replace(/[^\w]/g, '\\$&') будет работать таким же образом.
  • 0
    альтернатива: .replace(/\W/g, "\\$&");
7

Существует предложение ES7 для RegExp.escape в https://github.com/benjamingr/RexExp.escape/, а polyfill доступно https://github.com/ljharb/regexp.escape.

4

Это более короткая версия.

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

Это включает неметаные символы %, &, ' и ,, но спецификация JavaScript RegExp позволяет это.

  • 2
    Я бы не стал использовать эту «более короткую» версию, поскольку диапазоны символов скрывают список символов, что затрудняет проверку правильности на первый взгляд.
  • 0
    @nhahtdh Я, вероятно, не хотел бы, но это размещено здесь для информации.
Показать ещё 3 комментария
1
escapeRegExp = function(str) {
  if (str == null) return '';
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
0

I Googled для онлайн-инструмента, который сделает это, но на удивление не смог найти его. Мог бы обернуться, чтобы однажды сбить кого-то, чтобы заткнуть промежуток, но в то же время сделал простой скрипт JS из принятого ответа:

https://jsfiddle.net/xnd0bkne/

StackOverflow требует, чтобы код был опубликован для скрипта JS, так что вот оно:

var s = prompt("Enter text to be REGEX-ESCAPED: ");
prompt("REGEX-ESCAPED (please select and copy the text below): ",
       s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'));
0

Вместо того, чтобы избегать символов, которые могут вызвать проблемы в вашем регулярном выражении (например, черный список), почему бы не использовать вместо этого белый список. Таким образом, каждый символ считается испорченным, если он не соответствует.

В этом примере предположим следующее выражение:

RegExp.escape('be || ! be');

Это белый список букв, цифр и пробелов:

RegExp.escape = function (string) {
    return string.replace(/([^\w\d\s])/gi, '\\$1');
}

Возврат:

"be \|\| \! be"

Это может ускользнуть от символов, которые не должны быть экранированы, но это не мешает вашему выражению (возможно, незначительные штрафные санкции - но это того стоит для безопасности).

0

XRegExp имеет функцию escape:

XRegExp.escape('Escaped? <.>'); // -> 'Escaped\?\ <\.>'

Подробнее: http://xregexp.com/api/#escape

-2

Функции в других ответах являются излишними для экранирования всех регулярных выражений (они могут быть полезны для экранирования частей регулярных выражений, которые позже будут объединены в большие регулярные выражения).

Если вы избегаете всего регулярного выражения и выполняетесь с ним, цитируя метасимволы, которые являются автономными (., ?, +, *, ^, $, |, \) или начать что-то ((, [, {) - все, что вам нужно:

String.prototype.regexEscape = function regexEscape() {
  return this.replace(/[.?+*^$|({[\\]/g, '\\$&');
};

И да, это разочаровывает, что JavaScript не имеет такой функции, как этот встроенный.

  • 0
    Допустим, вы избегаете пользовательского ввода (text)next и вставляете его в: (?: + Input + ) . Ваш метод выдаст результирующую строку (?:\(text)next) которая не скомпилируется. Обратите внимание, что это вполне разумная вставка, а не какая-то сумасшедшая, например re\ + input + re (в этом случае программиста можно обвинить в том, что он сделал глупость)
  • 1
    @nhahtdh: в моем ответе конкретно говорилось о том, что нужно избегать целых регулярных выражений и «завершаться» с ними, а не частями (или будущими частями) регулярных выражений. Пожалуйста, отмените понижающий голос?
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню