RegEx для сопоставления специальных шаблонов - PullRequest
3 голосов
/ 27 мая 2019

Я пытаюсь сопоставить строку следующим образом: 62.00|LQ+2*2,FP,MD*3 "Description" Если десятичное значение является необязательным 2-значным, для каждого пользователя характерны два символа, за которыми может следовать

(\ + [\ d] +)? или (\ * [\ d] +)? или нет, или оба, или оба в другом порядке

как:

LQ * 2 + 4 | LQ + 4 * 2 | LQ * 2 | LQ + 8 | LQ

Описание также необязательно

Я попробовал вот что:

Pattern.compile("^(?<number>[\\d]+(\\.[\\d]{2})?)\\|(?<users>([A-Z]{2}){1}(((\\+[\\d]+)?(\\*[\\d]+)?)|((\\+[\\d]+)?(\\*[\\d]+)?))((,[A-Z]{2})(((\\+[\\d]+)?(\\*[\\d]+)?)|((\\+[\\d]+)?(\\*[\\d]+)?)))*)(\\s\\\"(?<message>.+)\\\")?$");

Мне нужно получить всех пользователей, чтобы я мог разделить их на ',' и затем еще раз пересмотреть мой путь в него. Но я ничего не могу извлечь из него. Желаемый вывод из

62,00 | LQ + 2 * 2, FP, MD * 3 "Описание"

Должно быть:

62,00

LQ + 2 * 2, FP, MD * 3

Описание

Допустимые входные данные должны быть следующих типов:

62,00 | LQ + 2 * 2, FP, MD * 3

30 | LQ "Бургеры"

35,15 | LQ * 2, FP + 2 * 4, MD * 3 + 4 "Картофель"

35,15 | LQ, FP, MD

Ответы [ 2 ]

3 голосов
/ 27 мая 2019

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

^(\d+(?:\.\d{1,2})?)\|([a-zA-Z]{2}(?:(?:\+\d+(?:\*\d+)?)|(?:\*\d+(?:\+\d+)?))?(?:,[a-zA-Z]{2}(?:(?:\+\d+(?:\*\d+)?)|(?:\*\d+(?:\+\d+)?))?)*)(?: +(.+))?$

Где group1 будет содержать число, которое может иметь необязательные десятичные дроби до двух цифр, а group2 будет иметь разделенные запятыми входные данные, как вы описали в своем посте, а group3 будет содержать необязательное описание, если оно присутствует.

Объяснение регулярного выражения:

  • ^ - начало строки
  • (\d+(?:\.\d{1,2})?) - соответствует номеру, который может иметь необязательные 2 цифры после запятой, и захватывает его в группе 1
  • \| - Соответствует литералу |, присутствующему в вашем вводе после числа
  • ([a-zA-Z]{2}(?:(?:\+\d+(?:\*\d+)?)|(?:\*\d+(?:\+\d+)?))?(?:,[a-zA-Z]{2}(?:(?:\+\d+(?:\*\d+)?)|(?:\*\d+(?:\+\d+)?))?)*) - эта часть соответствует двум буквам, за которыми следует любая комбинация + с последующим номером и, при необходимости, * с последующим номером ИЛИ * с последующим номером и, при желании, с +, за которым следует либо номер, либо один раз или все это необязательно и захватывает его в group2
  • (?: +(.+))? - Это соответствует необязательному описанию и захватывает его в group3
  • $ - отмечает конец ввода

Regex Demo

1 голос
/ 27 мая 2019

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


RegEx 1

Если мы просто сопоставляем все, что я предполагаю, мы могли бы начать с чего-то похожего на:

[0-9]+(\.[0-9]{2})?\|[A-Z]{2}[+*]?([0-9]+)?[+*]?([0-9]+)?,[A-Z]{2},[A-Z]{2}[+*]?([0-9]+)?(\s+"Description")?

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

Если нам нравится захватывать, тогда мы просто оборачиваем любую часть, которую хотим захватить, группой захвата ().

Демо

Тест

import java.util.regex.Matcher;
import java.util.regex.Pattern;

final String regex = "[0-9]+(\\.[0-9]{2})?\\|[A-Z]{2}[+*]?([0-9]+)?[+*]?([0-9]+)?,[A-Z]{2},[A-Z]{2}[+*]?([0-9]+)?(\\s+\"Description\")?";
final String string = "62.00|LQ+2*2,FP,MD*3 \"Description\"\n"
     + "62|LQ+2*2,FP,MD*3 \"Description\"\n"
     + "62|LQ+2*2,FP,MD*3\n"
     + "62|LQ*2,FP,MD*3\n"
     + "62|LQ+8,FP,MD*3\n"
     + "62|LQ,FP,MD";

final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);

while (matcher.find()) {
    System.out.println("Full match: " + matcher.group(0));
    for (int i = 1; i <= matcher.groupCount(); i++) {
        System.out.println("Group " + i + ": " + matcher.group(i));
    }
}

RegEx 2

Если мы хотим вывести три группы из списка:

([0-9]+(\.[0-9]{2})?)\|([A-Z]{2}[+*]?([0-9]+)?[+*]?([0-9]+)?,[A-Z]{2},[A-Z]{2}[+*]?([0-9]+)?)(\s+"Description")?

Демо 2

Тест

import java.util.regex.Matcher;
import java.util.regex.Pattern;

final String regex = "([0-9]+(\\.[0-9]{2})?)\\|([A-Z]{2}[+*]?([0-9]+)?[+*]?([0-9]+)?,[A-Z]{2},[A-Z]{2}[+*]?([0-9]+)?)(\\s+\"Description\")?";
final String string = "62.00|LQ+2*2,FP,MD*3 \"Description\"\n"
     + "62|LQ+2*2,FP,MD*3 \"Description\"\n"
     + "62|LQ+2*2,FP,MD*3\n"
     + "62|LQ*2,FP,MD*3\n"
     + "62|LQ+8,FP,MD*3\n"
     + "62|LQ,FP,MD";
final String subst = "\\1\\n\\3\\n\\7";

final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);

// The substituted value will be contained in the result variable
final String result = matcher.replaceAll(subst);

System.out.println("Substitution result: " + result);

RegEx 3

На основании обновленного желаемого результата это может работать:

([0-9]+(\.[0-9]{2})?)\|((?:[A-Z]{2}[+*]?([0-9]+)?[+*]?([0-9]+)?,?)(?:[A-Z]{2}[+*]?([0-9]+)?[*+]?([0-9]+)?,?[A-Z]{2}?[*+]?([0-9]+)?[+*]?([0-9]+)?)?)(\s+"(.+?)")?

DEMO

...