2016-04-15 2 views
0

Я увидел здесь вопрос SO, который использует Java Matcher и Pattern, пытаясь выделить текст, похожий на то, как он выделяет Regex101. Его спецификация заключалась в том, чтобы выделить в JTextArea для любой литеральной строки, которой не предшествует буквальный символ «#». Я собирался предложить создать свой собственный Matcher, а затем OP удалил свой вопрос :(Regex для захвата «WORD», кроме как после «#»

Это был фон, теперь вот мой вопрос. Как я могу использовать регулярное выражение, чтобы захватить литеральную строку, если это не после (но нет необходимости смежно) конкретная строка/символ в строке?

Например, если я хотел, чтобы выбрать строку «тестер» из следующего

тестер, #tester

тест тестер # тест тестер

тестер

Я надеюсь, что мое регулярное выражение будет выбрать

тестера, #tester

теста тестера # тест тестер

тестер

но не последний «тестер».

Использование Regex101, ближайший я получил /(?=tester)(?<!#)tester/g, но это выбирает последнюю строку «тестера», так как я не могу сделать «динамический»? (отличная от нуля), оглядываясь назад, насколько я могу судить.

EDIT:

Мой вопрос был не Java конкретно, в противном случае я бы, поставил метку Java. Если Regex101 не так, я не могу использовать Limiting Repetition, потому что «Lookbehinds должны быть нулевой ширины, поэтому квантификаторы не допускаются».

Я тестировал регулярное выражение WiktorStribiżew на Java, и он отлично работает. Видя, что это комментарий, а не ответ, все, что я могу сделать, это +1, Java String - (?<!#.{0,1000})\\btester\\b. Я протестировал его против следующего Java String tester, #tester\ntest tester # test testern\tester

Вопрос о том, что не существует полностью определенного способа обработки регулярных выражений на всех языках? Или есть Regex101 просто плохой инструмент тестирования (я использовал свой механизм по умолчанию, PHP)?

В будущем я буду использовать RegexStorm или RegexHero.

+0

https://regex101.com/r/aT3qN3/6 – Shafizadeh

+0

Тогда он должен быть только один символ, который является уникальным в этой строке , –

+0

Почему вы не можете просто проверить свой желаемый персонаж?/(? = tester) #?/g –

ответ

0

Вы можете использовать необязательную группу до tester, которая начинается с #. Затем проверьте наличие первой группы и замените ее соответствующим образом.

String text = "tester, #tester\ntester foo\ntest tester # test tester\ntester"; 
Pattern p = Pattern.compile("(#[^#\n]*)?(\\btester\\b)"); 
Matcher m = p.matcher(text); 

StringBuffer sb = new StringBuffer(); 
while(m.find()) { 
    if (m.group(1) == null) 
     m.appendReplacement(sb, "<em>" + m.group(2) + "</em>"); 
    else 
     m.appendReplacement(sb, m.group()); 
} 
m.appendTail(sb); 
System.err.println(sb); 

Выход:

<em>tester</em>, #tester 
<em>tester</em> foo 
test <em>tester</em> # test tester 
<em>tester</em> 
0

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

JTextArea textArea = new JTextArea(10, 30); 

    String text = "test tester # test tester"; 

    textArea.setText(text); 

    Highlighter highlighter = textArea.getHighlighter(); 
    HighlightPainter painter = 
     new DefaultHighlighter.DefaultHighlightPainter(Color.pink); 
    int p0 = text.indexOf("tester"); 
    int p1 = p0 + "tester".length(); 
    highlighter.addHighlight(p0, p1, painter); 

    JOptionPane.showMessageDialog(null, new JScrollPane(textArea)); 

Если применить только подсветку, когда p0==0 или text.charAt(p0-1) != '#' вам не нужно регулярное выражение. (Или когда p0 < text.indexOf("#"), я не уверен, что вы хотите точно.)

1

В Java, вы можете использовать ограничен шириной, что назад 'это удобно, если количество символов до ожидаемого подстроки не бесконечна. Это означает, что вы можете использовать ограничивающий квантификатор внутри lookbehind. (Существует ошибка, которая позволяет использовать * в Java 8, но использовать ее не рекомендуется, поскольку в дальнейших версиях ошибка может быть исправлена.) Отметим, что при больших значениях внутри предельного квантора производительность может снизиться.

Таким образом, вы можете использовать

String rx = "(?<!#.{0,1000})\\btester\\b"; 

Смотрите IDEONE demo

картина соответствует любому целому слову tester (как \b является границей слова), не предшествуют с # следует с 0 до 1000 любые символы, но символ новой строки (с DOTALL, он также будет соответствовать символам новой строки).

Примечание на онлайн ТЕСТЕРОВ: Поскольку regex101 не поддерживает регулярные выражения ароматизаторов (например, Java или ICU), которые имеют ширину ограничен-просмотра назад. Используйте онлайн-тестеры на базе .NET, например RegexStorm или RegexHero. Или просто используйте лучшие онлайн-тестеры Java regex: RegexPlanet или ocpsoft.


Теперь говоря о решении общего: Match what you do not need, and match and capture what you need to keep..

Это the pattern:

#.*\btester\b|\b(tester)\b 

Обратите внимание, что в зеленом особо tester s являются те, которые находятся в группе захвата # 1, а те, в группе 0 в синем на regex101. Вы можете проверить, к какой группе относятся эти подвалы, и принять соответствующие меры в коде.

В Java, чтобы проверить, если группа совпадают, просто использовать

if (match.group(1) != null) { 
    /* Group 1 matched, the tester we need is here */ 
} 
else { 
    /* No action, this tester is preceded with # */ 
} 
+0

Я обновлялся с самым общим подходом. –

Смежные вопросы