Regex Lookahead и Lookbehinds: за ними следует то или иное

Я пытаюсь написать регулярное выражение, которое проверяет заранее, чтобы убедиться, что после слов, которые я ищу, есть либо символ пробела, либо открывающая скобка. Кроме того, я хочу, чтобы он оглянулся назад и убедился, что ему предшествует либо не-Word (\W), либо вообще ничего (т.е. это начало оператора).

До сих пор у меня есть,

"(\\W?)(" + words.toString() + ")(\\s | \\()"

Однако это также соответствует материалу на обоих концах - я хочу, чтобы этот шаблон соответствовал ТОЛЬКО самому слову, а не материалу вокруг него.

Я использую Regex с ароматом Java.


person CodyBugstein    schedule 30.05.2013    source источник
comment
Если это регулярное выражение соответствует строке, оно будет иметь 4 группы. Первым будет вся строка, третьим будет слово, которое вы ищете.   -  person sbk    schedule 30.05.2013


Ответы (3)


Поскольку вы сами отметили свой вопрос, вам нужны осмотры:

String regex = "(?<=\\W|^)(" + Pattern.quote(words.toString()) + ")(?= |[(])"
  • (?<=X) означает "предшествует X"
  • (?<!=X) означает, что "не предшествует X"
  • (?=X) означает "за которым следует X"
  • (?!=X) означает "не, за которым следует X"
person sp00m    schedule 30.05.2013
comment
Всегда используйте Pattern.quote(), когда вы вставляете какую-либо простую строку в регулярное выражение. А (?<=\\W|^) можно сократить до (?!\w). Также обратите внимание, что (?= |[(]) должно быть (?= | [(]) - person nhahtdh; 30.05.2013
comment
@nhahtdh Можете ли вы привести пример с Pattern.quote()? я не уверен, что ты имеешь в виду - person CodyBugstein; 30.05.2013
comment
Не могли бы вы предоставить вывод words.toString()? - person sp00m; 30.05.2013
comment
Просто проверьте документацию, Pattern.quote(String). Он будет экранировать метасимволы в строке перед вставкой в ​​​​шаблон. - person nhahtdh; 30.05.2013

А как насчет самого слова: всегда ли оно будет начинаться с символа слова (то есть с того, который соответствует \w)? Если это так, вы можете использовать границу слова для начального условия.

"\\b" + theWord + "(?=[\\s(])"

В противном случае вы можете использовать отрицательный просмотр назад:

"(?<!\\w)" + theWord + "(?=[\\s(])"

Я предполагаю, что слово либо цитируется так:

String theWord = Pattern.quote(words.toString());

... или не должно быть.

person Alan Moore    schedule 30.05.2013

Если вы не хотите, чтобы группа захватывалась сопоставлением, вы можете использовать специальную конструкцию (?:X)

Итак, в вашем случае:

"(?:\\W?)(" + words.toString() + ")(?:\\s | \\()"

Тогда у вас будет только две группы: group(0) для всей строки и group(1) для искомого слова.

person Cyrille Ka    schedule 30.05.2013
comment
Я считаю, что вопрос не в захвате, а в сопоставлении: (?:) не захватит группу, но она все равно будет сопоставлена. - person sp00m; 30.05.2013
comment
Это путаница в лексике. OP хочет сопоставить слово, которому предшествует некоторая конструкция C1, а за ним следует некоторая конструкция C2, и получить только слово между ними. Он может сделать это, либо используя поиск, как в вашем ответе, либо сопоставив все это и получив часть, которую он хочет, как в моем. Результат будет таким же, и я думаю, что вопрос ОП касается получения данных, а не того, как использовать конкретный метод, но я могу ошибаться. - person Cyrille Ka; 30.05.2013
comment
@CyrilleKa Вы правы; Я просто хочу получить данные, которые мне нужны, и если лучший способ не использовать обходные пути, это тоже здорово. Тем не менее, ваш ответ не работает для меня... - person CodyBugstein; 30.05.2013
comment
Вам придется рассказать нам больше о том, как это не работает. Опубликуйте, например, SSCCE и сообщите нам, чего вы ожидаете и что получаете. - person Cyrille Ka; 30.05.2013
comment
Что ж, я создаю String под названием regex, используя ваши слова сверху со словами внутри hello|goodbye. Я передаю его как параметр здесь: Pattern.compile(regex) затем я создаю сопоставление по pattern.matcher("hello yo and BIGhello and have a goodbye"). Когда я запускаю цикл while с matcher.find(), он ничего не находит. - person CodyBugstein; 30.05.2013
comment
(?:\W?) будет соответствовать символу, не являющемуся словом, если он есть, но не будет предотвращать совпадение, если там есть символ слова. А в другой группе вам нужно удалить эти пробелы (например, (?:\s|\(), но вы также можете сжать это до [\s(], как я сделал в своем ответе). - person Alan Moore; 31.05.2013