Регулярное выражение для соответствия [] но не \[\]

Как я могу получить все совпадения для [.*], но не в том случае, если скобки экранированы обратной косой чертой, например \[.*\]?

Я могу использовать функцию JavaScript new RegExp("\\[.*\\]", "g"), чтобы получить все [.*]. Как я могу исключить все \[.*\] (экранированные скобки)?

Ввод выглядит следующим образом:

div\[data-custom-attribute='References'\][matchme]

В этом случае регулярное выражение должно соответствовать [matchme].


person MR.ABC    schedule 24.06.2013    source источник
comment
Почему бы не использовать литералы регулярных выражений для создания регулярного выражения, чтобы исключить необходимость двойного экранирования обратной косой черты? /\[.*\]/g   -  person hugomg    schedule 24.06.2013


Ответы (3)


http://rubular.com/r/16q3jSPHN0

[^\\](?:\]?(\[(.+?)\])) должно работать в большинстве случаев.

Изменить:

Похоже, это не будет соответствовать \[test\][test], как указал Рори. Для этого я не могу придумать хорошее решение без использования нескольких регулярных выражений, но если вам нужно только одно, попробуйте следующее: http://rubular.com/r/QBqFAbqW9E

(?:[^\\](?:\]?(\[(.+?)\]))|((?:\]?(\[(.+?)\])))\\)

Группы соответствия будут заполнены в первые 3, если блок с экранированными скобками встречается после обычного блока, и в последние 3, если происходит обратное.

Match 1
1.   
2.   
3.  [test]
4.  [test]
5.  test
Match 2
1.  [test]
2.  test
3.   
4.   
5.   
person dav    schedule 24.06.2013
comment
JavaScript не поддерживает lookbehind, так что это лучшее, что вы можете сделать. Но если бы это делал JavaScript, было бы лучше заменить [^\\] на (?<!\\), чтобы можно было сопоставлять строки, начинающиеся с [, например [test]\[test\] (до, после). - person Rory O'Kane; 24.06.2013
comment
@ РориО'Кейн, ты прав. Я думаю, было бы разумно использовать два выражения, по одному для каждого случая, по крайней мере, в том, что касается JS. В качестве альтернативы я обновил свой комментарий одним выражением, которое, кажется, улавливает оба случая, но смещает сгруппированные результаты в зависимости от положения экранированных блоков. Лучшего решения не придумаешь. - person dav; 24.06.2013
comment
Почему ваши тестовые строки не содержат обратной косой черты? Одна обратная косая черта в строке экранирует следующий символ (если есть), поэтому ваши одиночные обратные косые черты на самом деле не являются частью строки, а это означает, что вы не проверяете данные точно. В реальном примере ваше первое регулярное выражение не работает: jsfiddle.net/A6XBH/1 - person Ian; 24.06.2013
comment
Обратите внимание, что в [foo][bar][baz] он будет соответствовать только bar. И да, в JS вы не можете добиться большего, чем использовать (?:^|[^\\]) вместо [^\\]. - person Qtax; 24.06.2013
comment
@dav я буду использовать 2 запроса регулярных выражений. как я могу получить 2 совпадения вместо 1 для [data-custom-attribute='References'][matchme]? - person MR.ABC; 24.06.2013
comment
@Abc Оглядываясь назад, я думаю, что было бы лучше, если бы вы использовали одно регулярное выражение, чтобы найти все экранированные блоки, удалить их (например, заменить на ""), а затем использовать другое регулярное выражение, чтобы найти все обычные блоки. Примерно так: jsfiddle.net/A6XBH/2 - person dav; 24.06.2013

Самая большая проблема заключается в том, чтобы понять, смотрите ли вы на экранированную скобку (\[) или на скобку, которая следует за экранированной обратной косой чертой (\\[). Это достаточно просто, если вы ищете только одно совпадение:

/^[^\]\[\\]*(?:\\.[^\]\[\\]*)*(\[[^\]\[]+\])/

Первая часть поглощает любые символы, кроме обратной косой черты или квадратных скобок. Если он видит обратную косую черту, он захватывает его и следующий символ, каким бы он ни был. Он повторяет этот процесс столько раз, сколько может, и когда он больше не может этого делать, следующей вещью должно быть значение в квадратных скобках (или «тег»), которое вы ищете. Он захвачен в группе №1.

Получить остальные теги сложнее. Чтобы синхронизировать данные, вы хотите, чтобы каждое последующее совпадение начиналось точно с того места, где закончилось предыдущее совпадение. Многие разновидности регулярных выражений поддерживают привязку \G именно для этой цели, но нам это не помогает. JavaScript находится в процессе принятия флага /y, который, по сути, делает то же самое, но вы пока не можете на это рассчитывать.

Вот обходной путь, который должен работать в случае:

/(?:^|\[[^\]\[]+\])[^\]\[\\]*(?:\\.[^\]\[\\]*)*(?=(\[[^\]\[]+\]))/g

Базовое регулярное выражение такое же, но группа захвата теперь находится внутри просмотра вперед. В первый раз поиск начинается с начала строки, как и раньше, но останавливается сразу после первого тега. Упреждающий просмотр подтверждает, что тег присутствует, но не использует его. Следующее совпадение начинается с повторного сопоставления тега, что требует времени. Между тем, тег также фиксируется в группе № 1, поэтому вы можете получить к нему доступ обычным способом.

var regex = /(?:^|\[[^\]\[]+\])[^\]\[\\]*(?:\\.[^\]\[\\]*)*(?=(\[[^\]\[]+\]))/g;
var match = regex.exec(subject);
while (match != null) {
    // tag is in match[1]
    match = regex.exec(subject);
}
person Alan Moore    schedule 24.06.2013

Используйте неперехватываемую группу, например [^\\] :

[^\\]\[.*[^\\]\]
person zessx    schedule 24.06.2013
comment
Я думаю, что фраза, которую вы ищете, - это незахватывающая группа, но то, что у вас есть, на самом деле является отрицательным классом символов, и это не решает проблему. Во-первых, ваше регулярное выражение не будет соответствовать [test] в начале строки, потому что оно должно потреблять символ перед открытием [. Возможно, вы думаете об отрицательном просмотре назад, но JavaScript их не поддерживает. - person Alan Moore; 24.06.2013