从字符串中提取不规则数字数据

时间:2016-12-09 18:48:04

标签: r regex string

我有如下数据。我希望从名为my.string的每个字符串中提取第一年和最后一年。有些字符串只包含一年,有些字符串不包含年份。没有字符串包含超过两年。我在示例数据集下面的名为desired.result的对象中提供了所需的结果。我正在使用R

当字符串包含两年时,这些年份包含在字符串的一部分中,该字符串看起来像ga49.51ea22.24

当一个字符串只包含一年时,该字符串的一部分包含在该字符串的一部分中:time11

我对regex了解一点,但这个问题看起来太不规则和复杂了。我甚至不知道从哪里开始。谢谢你的任何建议。

修改

也许删除第一个冒号(:)之前的数字,剩下的数字就是我想要的。

my.data <- read.table(text = '

                my.string  cov1 cov2

           42:Alpha:ga6.8  -0.1  2.2
          43:Alpha:ga9.11  -2.5  0.6
         44:Alpha:ga30.32  -1.3  0.5
         45:Alpha:ga49.51  -2.5  0.6
   50:Alpha:time1:ga.time  -1.7  0.9
   51:Alpha:time2:ga.time  -1.5  0.8
   52:Alpha:time3:ga.time  -1.0  1.0
             2:Beta:ea2.9  -1.7  0.6
           3:Beta:ea17.19  -5.0  0.8
           4:Beta:ea22.24  -6.4  1.0
                8:Beta:as   0.2  0.6
                9:Beta:sd   1.7  0.4
     12:Beta:time1:ea.tim  -2.6  1.8
     13:Beta:time10:ea.ti  -3.6  1.1
     14:Beta:time11:ea.ti  -3.1  0.7

', header = TRUE, stringsAsFactors = FALSE, na.strings = "NA")

desired.result <- read.table(text = '

                my.string  cov1 cov2  time1  time2

           42:Alpha:ga6.8  -0.1  2.2      6      8
          43:Alpha:ga9.11  -2.5  0.6      9     11
         44:Alpha:ga30.32  -1.3  0.5     30     32
         45:Alpha:ga49.51  -2.5  0.6     49     51
   50:Alpha:time1:ga.time  -1.7  0.9      1     NA
   51:Alpha:time2:ga.time  -1.5  0.8      2     NA
   52:Alpha:time3:ga.time  -1.0  1.0      3     NA
             2:Beta:ea2.9  -1.7  0.6      2      9
           3:Beta:ea17.19  -5.0  0.8     17     19
           4:Beta:ea22.24  -6.4  1.0     22     24
                8:Beta:as   0.2  0.6     NA     NA
                9:Beta:sd   1.7  0.4     NA     NA
     12:Beta:time1:ea.tim  -2.6  1.8      1     NA
     13:Beta:time10:ea.ti  -3.6  1.1     10     NA
     14:Beta:time11:ea.ti  -3.1  0.7     11     NA

', header = TRUE, stringsAsFactors = FALSE, na.strings = "NA")

2 个答案:

答案 0 :(得分:2)

我建议使用 stringr 库来提取您需要的数据,因为它可以更好地处理NA值,并且还允许使用约束宽度 lookbehind:

> library(stringr)
> my.data$time1 <- str_extract(my.data$my.string, "(?<=time)\\d+|(?<=\\b[ge]a)\\d+")
> my.data$time2 <- str_extract(my.data$my.string, "(?<=\\b[ge]a\\d{1,100}\\.)\\d+")
> my.data
                my.string cov1 cov2 time1 time2
1          42:Alpha:ga6.8 -0.1  2.2     6     8
2         43:Alpha:ga9.11 -2.5  0.6     9    11
3        44:Alpha:ga30.32 -1.3  0.5    30    32
4        45:Alpha:ga49.51 -2.5  0.6    49    51
5  50:Alpha:time1:ga.time -1.7  0.9     1  <NA>
6  51:Alpha:time2:ga.time -1.5  0.8     2  <NA>
7  52:Alpha:time3:ga.time -1.0  1.0     3  <NA>
8            2:Beta:ea2.9 -1.7  0.6     2     9
9          3:Beta:ea17.19 -5.0  0.8    17    19
10         4:Beta:ea22.24 -6.4  1.0    22    24
11              8:Beta:as  0.2  0.6  <NA>  <NA>
12              9:Beta:sd  1.7  0.4  <NA>  <NA>
13   12:Beta:time1:ea.tim -2.6  1.8     1  <NA>
14   13:Beta:time10:ea.ti -3.6  1.1    10  <NA>
15   14:Beta:time11:ea.ti -3.1  0.7    11  <NA>

第一个正则表达式匹配:

  • (?<=time)\\d+ - 在他们之前有time的1位数字
  • | - 或
  • (?<=\\b[ge]a)\\d+ - 前面有ge或ea`作为整个单词的1位数字

第二个正则表达式匹配:

  • (?<=\\b[ge]a\\d{1,100}\\.) - 检查当前位置是否以geea作为整个单词后跟1到100位数(我相信这对于您的方案应该足够了,100 - 这里几乎没有预期的数据块,你甚至可以减少这个数值),然后是.
  • \\d+ - 1+位数

答案 1 :(得分:1)

这是一个正则表达式,它将提取两种类型中的任何一种,并将它们输出到行尾的不同列:

搜索:.*(?:time(\d+)|(?:[ge]a)(\d+)\.(\d+)).*

替换:$0\t$1\t$2\t$3

<强>故障:

  • .*(?: ... ).*确保整条线匹配,并使用非捕获组进行主要更改
  • time(\d+):这是交替的前半部分,在“时间”之后捕获任何数字
  • (?:[ge]a)(\d+)\.(\d+):交替的后半部分匹配“ga”或“ea”,后跟两组数字,每组都在自己的捕获组中
  • 替换:$0将整条线放回去。将添加其他每个捕获组,并在其间添加选项卡。

See regex101 example