Поиск JavaScript с регулярным выражением, почему оператор плюс вызывает проблемы? [Дубликат]

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

  1. дает всем вашим элементам стиль.
  2. дает выбранный вами item style.
  3. дает следующие элементы стиль с использованием + или ~.

, и таким образом вы сможете стилизовать свои текущие предыдущие элементы (все элементы переопределены текущими и следующими элементами) и ваши следующие элементы.

пример:

/* all items (will be styled as previous) */
li {
  color: blue;
}

/* the item i want to distinguish */
li.milk {
  color: red;
}

/* next items */
li ~ li  {
  color: green;
}


<ul>
  <li>Tea</li>
  <li class="milk">Milk</li>
  <li>Juice</li>
  <li>others</li>
</ul>

Надеюсь, что это кому-то поможет.

327
задан Lance Pollard 24 August 2010 в 23:22
поделиться

12 ответов

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

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

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

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

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

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

И да, неутешительно, что это не является частью стандартного JavaScript.

410
ответ дан nhahtdh 18 August 2018 в 04:00
поделиться
  • 1
    на самом деле нам не нужно бежать / вообще – thorn 14 February 2013 в 22:53
  • 2
    @Paul: Perl quotemeta (\Q), Python re.escape, PHP preg_quote, Ruby Regexp.quote ... – bobince 3 October 2013 в 11:24
  • 3
    Если вы собираетесь использовать эту функцию в цикле, вероятно, лучше сделать объект RegExp своей собственной переменной var e = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;, а затем ваша функция return s.replace(e, '\\$&'); Таким образом вы только создадите экземпляр RegExp один раз. – styfle 17 October 2013 в 22:14
  • 4
    Здесь применяются стандартные аргументы против добавления встроенных объектов, нет? Что произойдет, если будущая версия ECMAScript предоставляет RegExp.escape, чья реализация отличается от вашей? Не лучше ли, чтобы эта функция не была привязана ни к чему? – Mark Amery 23 February 2015 в 18:16
  • 5

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

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

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

0
ответ дан Antoine Dusséaux 18 August 2018 в 04:00
поделиться

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

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

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

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

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

Возвраты:

"be \|\| \! be"

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

0
ответ дан bashaus 18 August 2018 в 04:00
поделиться

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

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

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

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

8
ответ дан daluege 18 August 2018 в 04:00
поделиться
  • 1
    Простой и эффективный. Мне это нравится намного лучше, чем принятый ответ. Для (действительно) старых браузеров .replace(/[^\w]/g, '\\$&') будет работать одинаково. – Tomas Langkaas 10 August 2017 в 07:20
  • 2
    Это не работает в режиме Unicode. Например, new RegExp(' – Alexey Lebedev 2 February 2018 в 11:29
  • 3
    альтернатива: .replace(/\W/g, "\\$&"); – Miguel Pynto 21 March 2018 в 15:34

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

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

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

И да, неутешительно, что JavaScript не имеет такой функции, как эта встроенная -в.

-1
ответ дан Dan Dascalescu 18 August 2018 в 04:00
поделиться
  • 1
    Предположим, вы избегаете пользовательского ввода (text)next и вставляете его в: (?: + ввод + ). Ваш метод даст результирующую строку (?:\(text)next), которая не скомпилируется. Обратите внимание, что это довольно разумная вставка, а не какой-то сумасшедший, такой как re\ + input + re (в этом случае программиста можно обвинять в том, что он делает что-то глупое) – nhahtdh 27 November 2014 в 03:58
  • 2
    @nhahtdh: в моем ответе конкретно упоминалось об исключении всех регулярных выражений и "выполнения" с ними, а не части (или будущие части) регулярных выражений. Пожалуйста, отмените нижний план? – Dan Dascalescu 27 November 2014 в 22:08
  • 3
    Редко бывает, что вы избежите всего выражения - есть операция строки, которая намного быстрее по сравнению с регулярным выражением, если вы хотите работать с литеральной строкой. – nhahtdh 28 November 2014 в 02:24
  • 4
    Это не означает, что это неверно - \ должно быть экранировано, так как ваше регулярное выражение оставит \w неповрежденным. Кроме того, JavaScript, похоже, не позволяет останавливать ), по крайней мере, это то, что Firefox вызывает ошибку. – nhahtdh 28 November 2014 в 02:30
  • 5
    Я избежал ответа `. Благодаря! – Dan Dascalescu 28 November 2014 в 02:33

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

Это нормально, но я предпочитаю подход «всегда работает».

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. [/ g 20]
  • !: Отклоняет группу нулевой ширины.
  • < / =: Часть спецификаций группы нулевой ширины.

Примечания :

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

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

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) : '') + ')');
28
ответ дан Gras Double 18 August 2018 в 04:00
поделиться
  • 1
    / не нужно экранировать в классе символов [...]. – Dan Dascalescu 4 July 2017 в 11:32
  • 2
    Большинство из них не нужно избегать. "Создает диапазон символов в символьном классе - вы никогда не находитесь в классе символов внутри строки. "Задает комментарий в режиме свободного интервала, игнорируется в режиме свободного пробела & quot; - не поддерживается в javascript. "Отделяет значения в спецификаторе нумерации - вы никогда не указываете спецификатор числа внутри строки. Также вы не можете писать произвольный текст внутри спецификации nameration. "Начинает или заканчивает выражение" - не нужно бежать. Eval - это не случай, так как это потребует гораздо большего выхода. [будет продолжено в следующем комментарии] – Qwertiy 22 September 2017 в 14:01
  • 3
    "Завершает специальные типы групп, а часть классов символов в стиле Perl - кажется недоступным в javascript. "Отрицает группу нулевой ширины, часть спецификаций групп нулевой ширины" - у вас никогда не будет групп внутри строки. – Qwertiy 22 September 2017 в 14:01
  • 4
    @Qwertiy Причина этих дополнительных побегов заключается в устранении краевых случаев, которые могут вызвать проблемы в некоторых случаях использования. Например, пользователь этой функции может захотеть вставить строку esgeed regex в другое регулярное выражение как часть группы или даже для использования на другом языке, кроме Javascript. Функция не делает предположений типа «Я никогда не буду частью класса символов», потому что это должно быть general . Для более подхода YAGNI см. Любой из других ответов здесь. – Pi Marillion 22 September 2017 в 20:14
  • 5
    Отлично. Почему же не удалось избежать? Что гарантирует его, вероятно, не станет синтаксисом regex позже? – madprops 29 October 2017 в 12:43

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

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

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

63
ответ дан gustavohenke 18 August 2018 в 04:00
поделиться
  • 1
    есть даже пакет npm только этого! npmjs.com/package/lodash.escaperegexp – Ted Pennings 1 November 2015 в 08:34
  • 2
    Имейте в виду, что функция loverash escapeRegExp также добавляет \ x3 в начало строки, не совсем уверен, почему. – maddob 28 July 2016 в 12:39
  • 3
    Это импортирует множество кода, который действительно не нужен для такой простой вещи. Используйте ответ bobince ... работает для меня и его так много меньше байтов для загрузки, чем версия lodash! – Rob Evans 31 August 2017 в 13:20
  • 4
    @RobEvans мой ответ начинается с & quot; Для всех, кто использует lodash & quot; , и я даже упоминаю, что вы можете требовать только функцию escapeRegExp. – gustavohenke 31 August 2017 в 13:24
  • 5
    @gustavohenke Извините, я должен был быть немного более ясным, я включил модуль, связанный с вашей "только этой функцией & quot; и это то, о чем я комментировал. Если вы посмотрите, это довольно много кода для того, что должно эффективно быть одной функцией с одним регулярным выражением в ней. Согласитесь, если вы уже используете lodash, тогда имеет смысл использовать его, но в противном случае используйте другой ответ. Извините за неясный комментарий. – Rob Evans 31 August 2017 в 18:03
  • 6
    – Federico Fissore 31 May 2018 в 15:10

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

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

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

4
ответ дан kzh 18 August 2018 в 04:00
поделиться
  • 1
    Я бы не использовал этот «более короткий». поскольку диапазоны символов скрывают список символов, что затрудняет проверку правильности на первый взгляд. – nhahtdh 27 November 2014 в 04:03
  • 2
    @nhahtdh Я, вероятно, тоже не был бы, но он размещен здесь для информации. – kzh 27 November 2014 в 13:15
  • 3
    @kzh: размещение & quot; для информации & quot; помогает меньше, чем размещать для понимания. Не могли бы вы согласиться с тем, что мой ответ более ясен? – Dan Dascalescu 27 November 2014 в 22:14
  • 4
    По крайней мере, . пропущен. И (). Или нет? [-^ странно. Я не помню, что там. – Qwertiy 22 September 2017 в 20:35
  • 5
    Они находятся в указанном диапазоне. – kzh 22 September 2017 в 21:15

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

RegExp.escape = function( value ) {
     return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
17
ответ дан Pierluc SS 18 August 2018 в 04:00
поделиться
  • 1
    Единственное отличие состоит в том, что они бегут , (что не является метасимволом) и # и пробелами, которые имеют значение только в режиме свободного пробела (который не поддерживается JavaScript). Тем не менее, они правильно понимают, что не сбежать от косой черты. – Martin Ender 8 July 2013 в 11:22
  • 2
    Если вы хотите повторно использовать реализацию jQuery UI, а не вставлять код локально, перейдите к $.ui.autocomplete.escapeRegex(myString). – Scott Stafford 19 August 2013 в 19:37
  • 3
    У lodash тоже есть, _. escapeRegExp и npmjs.com/package/lodash.escaperegexp – Ted Pennings 1 November 2015 в 08:35
  • 4
    v1.12 то же самое, ок! – Peter Krauss 7 March 2017 в 04:27
escapeRegExp = function(str) {
  if (str == null) return '';
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
1
ответ дан pzaenger 18 August 2018 в 04:00
поделиться

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

7
ответ дан user 18 August 2018 в 04:00
поделиться

Руководство разработчика Mozilla Developer Network для регулярных выражений предоставляет эту функцию экранирования:

function escapeRegExp(string){
    return string.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1");
}
12
ответ дан user113215 18 August 2018 в 04:00
поделиться
  • 1
    Почему они избегают =? AFAIK, это было бы полезно для регулярных выражений Perl (?=), но если вы избежите ?, вам будет хорошо идти. – Dan Dascalescu 2 August 2014 в 01:51
  • 2
    @DanDascalescu Ты прав. Страница MDN обновлена, а = больше не включена. – user113215 7 August 2014 в 17:31
Другие вопросы по тегам:

Похожие вопросы: