Regex захватывает взгляд назад и вперед

Я пытаюсь написать регулярное выражение для следующих ситуаций:

badword%
%badword
%badword%

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

Вот чего я пытаюсь достичь. Если у меня есть следующее:

Просто обычная превосходная фраза.

badword   # should match "badword", easy enough
badword%  # should match "badwording"
%badword% # should match "superbadwording"

В то же время. Если у меня есть подобное предложение:

Вот еще один очень плохой пример.

badword   # should match "badword", easy enough
badword%  # should also match "badword"
%badword% # should match "verybadword"

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

Вот что у меня есть на Java:

String badword  = "%badword%";
String _badword = badword.replace("%", "");
badword = badword.replaceAll("^(?!%)%", "(?=\w)"); // match a % NOT at the beginning of a string, replace with look ahead that captures \w, not working
badword = badword.replaceAll("^%", "(?!=\w)"); // match a % at the beginning of a string, replace it with a look behind that captures \w, not working
System.out.println(badword); // ????

Итак, как я могу этого добиться?

PS: Пожалуйста, не думайте, что % принудительно переводятся в начало и конец матча. Если % является первым символом, тогда ему нужно будет смотреть назад, все остальные % смотрят вперед.


person Brian Graham    schedule 07.12.2013    source источник
comment
(?!%)% всегда будет терпеть неудачу, поскольку это означает, что за ним не следует %, а буквальный % (который следует за ним). (?!=\w) - это отрицательный просмотр вперед и означает, что за ним не следует литерал = и символ слова. В java необходимо экранировать обратную косую черту.   -  person Casimir et Hippolyte    schedule 07.12.2013


Ответы (2)


Из вашего вопроса, похоже, нет необходимости использовать поиск, поэтому вы можете просто заменить все % на \w*

Фрагмент:

String tested = "Just a regular superbadwording sentece.";
String bad = "%badword%";
bad = bad.replaceAll("%", "\\\\w*");
Pattern p = Pattern.compile(bad);
Matcher m = p.matcher(tested);
while(m.find()) {
    String found = m.group();
    System.out.println(found);
}

\ w не соответствует #, - и т. д. так что я думаю, что \ S здесь лучше

person LeonidasCZ    schedule 07.12.2013

badword = badword.replaceAll("^%", "(?!=\w)"); 
// match a % at the beginning of a string, replace it with a look behind 
//that captures \w, not working

(?!=\w) - это негативный взгляд на =\w, но похоже, что вам нужен позитивный взгляд назад. Во-вторых, просмотры вперед и назад являются атомарными и, следовательно, по своей сути не захватывают, поэтому, если я прав в своей интерпретации, вы хотите:

"(?<=(\\w+))". Вам понадобится дополнительный () для захвата. Для вашей первой части это будет: "(?=(\\w+)), а первый аргумент должен быть "(?<!^)%".

PS: Вам нужны две обратные косые черты для \\w, и вы, кажется, хотите сопоставить несколько символов, не так ли? Если так, вам понадобится \\w+. Кроме того, если вы не хотите делать это для каждого случая, я предлагаю использовать String.format() вместо replaceAll().

person Steve P.    schedule 07.12.2013
comment
Осмотр внутри группы захвата ничего не решает. Весь смысл поискового обхода в том, что он не потребляет то, что ему соответствует, поэтому даже если поисковый обход завершится успешно, все, что вы когда-либо собираетесь захватить в этой группе, - это пустая строка. - person Alan Moore; 08.12.2013
comment
@AlanMoore Глупая опечатка, я сделал это на своем телефоне. Теперь должно быть правильно. - person Steve P.; 08.12.2013