Как обрабатывать избыточные случаи в регулярных выражениях? - PullRequest
0 голосов
/ 02 декабря 2018

Я должен разобрать данные файла в хорошие и плохие записи, данные должны иметь формат

Patient_id::Patient_name (year of birth)::disease

Заболевания разделены трубами и выбраны из следующих:

1.HIV
2.Cancer
3.Flu
4.Arthritis 
5.OCD

Пример: 23 :: Alex.jr (1969) :: ВИЧ | Рак | грипп

Выражение регулярного выражения, которое я написал,

\d*::[a-zA-Z]+[^\(]*\(\d{4}\)::(HIV|Cancer|flu|Arthritis|OCD) 
     (\|(HIV|Cancer|flu|Arthritis|OCD))*

Но это такжерассматривая записи с избыточными записями

24 :: Робин (1980) :: ВИЧ | Рак | Рак | ВИЧ

Как обрабатывать записи такого рода и как написать лучшее выражение, еслисписок болезней очень большой.

Примечание: я использую задание hadoop maponly для анализа, поэтому дайте ответ в контексте с java.

Ответы [ 3 ]

0 голосов
/ 02 декабря 2018

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

^\d*::[a-zA-Z]+[^\(]*\(\d{4}\)::(?<disease>(?:HIV|Cancer|flu|Arthritis|OCD)(?:\|(?:HIV|Cancer|flu|Arthritis|OCD))*)$

Например:

String regex = "^\\d*::[a-zA-Z]+[^\\(]*\\(\\d{4}\\)::(?<disease>(?:HIV|Cancer|flu|Arthritis|OCD)(?:\\|(?:HIV|Cancer|flu|Arthritis|OCD))*)$";
String string = "24::Robin (1980)::HIV|Cancer|Cancer|HIV";

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

if (matcher.find()) {
    String[] parts =  matcher.group("disease").split("\\|");
    Set<String> uniqueDiseases = new HashSet<String>(Arrays.asList(parts));
    System.out.println(uniqueDiseases);
}

Результат:

[HIV, Cancer]

Regex demo | Java-демонстрация

0 голосов
/ 02 декабря 2018

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

^\d*::[a-zA-Z.]+\s\(\d{4}\)::((?:HIV|Cancer|flu|Arthritis|OCD|\|(?!\|))+)$

Он содержит:

  • ^ и $ якоря(вы хотите, чтобы строка вся соответствовала, а не ее часть).
  • Группа захвата, включая повторную группу без захвата (контейнер для альтернатив).Одна из этих альтернатив - |, но с отрицательным прогнозом на прямое следование | (таким образом, вы запрещаете 2 или более последовательных |).

Затем, если это регулярное выражение соответствуетДля конкретной строки вы должны:

  • Разделить группу № 1 на |.
  • Проверить результирующий массив строк на уникальность (он не должен содержать повторяющихся записей).

Только если проверка прошла успешно, вы должны принять соответствующую строку.

0 голосов
/ 02 декабря 2018

Вам нужен негативный взгляд .Попробуйте использовать это регулярное выражение: ^\d*::[^(]+?\s*\(\d{4}\)::(?!.*(HIV|Cancer|flu|Arthritis|OCD).*\|\1)((HIV|Cancer|flu|Arthritis|OCD)(\||$))+$.

Объяснение:

  1. Исходная строка ^\d*::[^(]+?\s*\(\d{4}\):: является только оптимизированной для соответствия Alex.jr примеру (ваша версия не учитывает никакие неалфавитные символы в именах)
  2. Блок отрицательного предпросмотра (?!.*(HIV|Cancer|flu|Arthritis|OCD).*\|\1) обозначает "ищет любое название болезни, встреченное дважды, и отклоняет строку, если найдена какая-либо. Его отличительной чертой является подпись (?! ... ).
  3. Наконец, ((HIV|Cancer|flu|Arthritis|OCD)(\||$))+$ также является оптимизированной версией вашего блока (HIV|Cancer|flu|Arthritis|OCD)(\|(HIV|Cancer|flu|Arthritis|OCD))*, ориентированной на избежание избыточного перечисления.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...