Регулярное выражение Java (java.util.regex). Искать знак доллара

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

"/bla/$V_N.$XYZ.bla";
"/bla/$V_N.$XYZ;

Я бы хотел вернуться:

  • V_N
  • XYZ

Если строка поиска содержит символы процента, я также хочу вернуть то, что находится между парой символов%.

Следующее регулярное выражение, похоже, помогает в этом.

 "%([^%]*?)%";

Вывод:

  • Начинайте и заканчивайте с%,
  • Создайте группу захвата - ()
  • иметь класс символов, содержащий что-либо, кроме символа% (каретка означает не символ)
  • повторил - но не жадно *?

Если некоторые языки позволяют использовать %1, %2 для групп захвата, Java вместо этого использует синтаксис backslash\number. Итак, эта строка компилируется и генерирует вывод.

Я подозреваю, что символ доллара и точка нужно экранировать, поскольку они являются специальными символами:

  • $ - обычно конец строки
  • . - это метапоследовательность для любого символа.

Я пробовал использовать символы двойной обратной косой черты .. \

  • Оба как классы персонажей. [^\\.\\$%]
  • и используя запись OR'd %|\\$

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

Интересно, сможет ли еще одна пара глаз увидеть, как решить эту загадку!

Мои попытки до сих пор:

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Main {
  public static void main(String[] args) {
        String search = "/bla/$V_N.$XYZ.bla";
        String pattern = "([%\\$])([^%\\.\\$]*?)\\1?";
  /* Either % or $ in first capture group ([%\\$])
   * Second capture group - anything except %, dot or dollar sign
   * non greedy group ( *?)
   * then a backreference to an optional first capture group \\1?
   * Have to use two \, since you escape \ in a Java string.
   */
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(search);
        List<String> results = new ArrayList<String>();
          while (m.find()) 
        { 
          for (int i = 0; i<= m.groupCount(); i++) {
                results.add(m.group(i));
          }
        }
        for (String result : results) {
          System.out.println(result);
        }
  }
}

Следующие ссылки могут быть полезны:


person JGFMK    schedule 12.11.2019    source источник


Ответы (1)


Вы можете использовать

String search = "/bla/$V_N.$XYZ.bla";
String pattern = "[%$]([^%.$]*)";
Matcher matcher = Pattern.compile(pattern).matcher(search);
while (matcher.find()){
    System.out.println(matcher.group(1)); 
} // => V_N, XYZ

См. демонстрацию Java и демонстрация регулярного выражения.

ПРИМЕЧАНИЕ

  • Вам не нужен необязательный \1? в конце шаблона. Поскольку это необязательно, он не ограничивает контекст сопоставления и является избыточным (поскольку отрицаемый класс символов уже не может соответствовать ни $, ни%)
  • [%$]([^%.$]*) соответствует % или $, затем захватывает в Группу 1 любые ноль или более символов, кроме %, . и $. Вам нужно только значение группы 1, следовательно, используется matcher.group(1).
  • В классе символов ни ., ни $ не являются специальными , таким образом, им не нужно экранировать в [%.$] или [%$].
person Wiktor Stribiżew    schedule 12.11.2019
comment
Думаю, мне понадобится не жадный поиск. - person JGFMK; 12.11.2019
comment
@JGFMK Нет, не знаешь. Класс инвертированных символов уже делает это. - person Wiktor Stribiżew; 12.11.2019
comment
Я подозреваю, что это не поможет сопоставить пары (при условии, что это требование). Например, попробуйте "/bla/$V_N%.$XYZ.bla" в качестве ввода - person ernest_k; 12.11.2019
comment
@ernest_k Это вызывает небольшую задержку в результатах. У вас получится пустая группа захвата. Но. К счастью, данные, которые у меня есть, всегда содержат либо пары знаков%, либо просто начинаются с символа $. Точка или последующий $ или конец строки могут быть концом того, что мне нужно захватить, если вещь начинается с символа $. Я всегда мог защитить себя, проверив длину группы (1), прежде чем добавлять ее к своим результатам. - person JGFMK; 12.11.2019
comment
@JGFMK Если вам нужно избегать пустых строк в результатах, все, что вам нужно, это + квантификатор в шаблоне: String pattern = "[%$]([^%.$]+)";. Я использовал * только потому, что следовал исходной логике шаблона, в которой использовался *?. - person Wiktor Stribiżew; 12.11.2019
comment
@ WiktorStribiżew Проблема оказалась более сложной. Я разместил здесь еще один вопрос: stackoverflow.com/questions/58827094/ Интересно, есть ли у вас какие-либо идеи по этому поводу? - person JGFMK; 13.11.2019
comment
@Holger К сожалению, текущий вопрос не отражает реальных требований. Я разместил более сложное решение, отвечающее более конкретным требованиям, здесь. - person Wiktor Stribiżew; 13.11.2019
comment
Я знаю, что есть дополнительный вопрос, однако есть общая проблема с утверждением, что необязательные совпадения в конце шаблона являются избыточными. Когда вы обрабатываете больше, чем первое совпадение, они актуальны. - person Holger; 13.11.2019
comment
@Holger Это будет иметь значение только для последовательных совпадений, и мое предложение учитывает логику OP. Здесь, \1? является избыточным, точка, я объяснил почему в своем ответе. Я не говорю, что необязательные шаблоны в конце шаблона всегда избыточны. - person Wiktor Stribiżew; 13.11.2019