我必须将文件数据解析为好记录和坏记录,数据的格式应为
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的上下文中给出答案。
答案 0 :(得分:0)
您需要负前瞻。
尝试使用以下正则表达式:^\d*::[^(]+?\s*\(\d{4}\)::(?!.*(HIV|Cancer|flu|Arthritis|OCD).*\|\1)((HIV|Cancer|flu|Arthritis|OCD)(\||$))+$
。
说明:
^\d*::[^(]+?\s*\(\d{4}\)::
只是一个经过优化的字符串,可以匹配 Alex.jr 示例(您的版本不使用名称中的任何非字母符号)(?!.*(HIV|Cancer|flu|Arthritis|OCD).*\|\1)
代表”,查找任何疾病名称,遇到两次,并拒绝该字符串(如果找到)。其独特之处是{{1} }签名。(?! ... )
也是块((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]
答案 2 :(得分:0)
可能更容易维护的方法是使用稍有变化的正则表达式, 如下所示:
^\d*::[a-zA-Z.]+\s\(\d{4}\)::((?:HIV|Cancer|flu|Arthritis|OCD|\|(?!\|))+)$
它包含:
^
和$
锚点(您希望匹配 entire 字符串,
而不是它的一部分。)|
,但带有负数
前瞻,以立即关注|
(这样一来,您不允许2或
更多连续的|
)。然后,如果此正则表达式与特定行匹配,则应:
|
分割组1。只有此检查成功,您才应接受有问题的行。