查找以不是下一场比赛的首字母的字母结尾的匹配项

时间:2017-10-30 16:13:04

标签: regex regex-lookarounds regex-greedy

简介

我有一个包含诊断代码(ICD-10)的字符串,没有任何字符分隔。我想提取所有有效的诊断代码。有效的诊断代码的格式为

[Letter] [2到4个数字] [不是下一个匹配首字母的可选字母]

这种模式的正则表达式是(我相信)

\w\d{2,4}\w?

示例

这是一个例子

mystring='F328AG560F33'

在此示例中,有三个代码:

'F328A' 'G560' 'F33'

我想在R中使用类似str_extract_all的函数提取这些代码(最好但不是唯一的)

到目前为止我的解决方案

到目前为止,我设法提出了一个表达式:

str_extract_all(mystring,pattern='\\w\\d{2,4}\\w?(?!(\\w\\d{2,4}\\w?))')

然而,当应用于上面的示例时,它返回

"F328"  "G560F"

基本上它错过了第一个代码中的字母A,并完全错过了最后一个代码" F33"错误地将F分配给前面的代码。

问题

我做错了什么?我只想提取以不是下一个匹配开头的字母结尾的值,如果是,则匹配不应该包含该字母。

应用

这个问题非常重要,例如在挖掘未经验证的患者电子健康记录时。

2 个答案:

答案 0 :(得分:2)

你有一个字母,两到四个数字,然后是一个可选的字母。那封可选的信件,如果它在那里,将只会跟着另一封信;或者,换句话说,从不跟随一个数字。你可以写一个负面的先行来捕捉这个:

\w\d{2,4}(?:\w(?!\d))?

这至少是works with PCRE。我不知道R将如何处理它。

答案 1 :(得分:1)

您的比赛重叠。在这种情况下,您可以使用str_match_all来轻松访问捕获组,并使用包含捕获组的正向前瞻模式:

(?i)(?=([A-Z]\d{2,4}(?:[A-Z](?!\d{2,4}))?))

请参阅regex demo

<强>详情

  • (?= - 一个积极的先行开始(它将在每个字符之前的每个位置和字符串末尾运行
  • ( - 第1组开始
    • [A-Z] - 一封信(如果您使用不区分大小写的修饰符(?i),则不区分大小写)
    • \d{2,4} - 2到4位
    • (?: - 可选的非捕获组开始:
      • [A-Z] - 一封信
      • (?!\d{2,4}) - 未跟随2到4位数字
    • )? - 可选的非捕获组结束
  • ) - 第1组结束
  • ) - Lookahead end。

R demo:

> library(stringr)
> res <- str_match_all("F328AG560F33", "(?i)(?=([A-Z]\\d{2,4}(?:[A-Z](?!\\d{2,4}))?))")
> res[[1]][,2]
[1] "F328A" "G560"  "F33"