如何处理正则表达式中的多余案例?

时间:2018-12-02 15:51:15

标签: regex parsing mapreduce hadoop2

我必须将文件数据解析为好记录和坏记录,数据的格式应为

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

疾病是管道分离的,并且选自以下疾病:

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

例如:23 :: Alex.jr(1969):: HIV | Cancer | flu

我写的正则表达式是

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

但是它也在考虑具有冗余条目的记录

24 :: Robin(1980):: HIV | Cancer | Cancer | HIV

如果疾病清单很大,如何处理此类记录以及如何写出更好的表达方式

注意:我正在使用hadoop maponly作业进行解析,因此请在使用Java的上下文中给出答案。

3 个答案:

答案 0 :(得分:0)

您需要负前瞻。 尝试使用以下正则表达式:^\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)代表”,查找任何疾病名称,遇到两次,并拒绝该字符串(如果找到)。其独特之处是{{1} }签名。
  3. 最后,(?! ... )也是块((HIV|Cancer|flu|Arthritis|OCD)(\||$))+$的优化版本,旨在避免重复列出。

答案 1 :(得分:0)

您可能要做的是捕获包含疾病的最后一部分(称为捕获组disease),然后使用split获得单个疾病,然后使列表唯一。

^\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 demo

答案 2 :(得分:0)

可能更容易维护的方法是使用稍有变化的正则表达式, 如下所示:

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

它包含:

  • ^$锚点(您希望匹配 entire 字符串, 而不是它的一部分。)
  • 捕获组,包括重复的非捕获组(容器 供选择)。这些选择之一是|,但带有负数 前瞻,以立即关注|(这样一来,您不允许2或 更多连续的|)。

然后,如果此正则表达式与特定行匹配,则应:

  • 通过|分割组1。
  • 检查结果字符串数组的唯一性(它不应包含 重复的条目)。

只有此检查成功,您才应接受有问题的行。