R - 正则表达式根据第一个点分隔字符串?

R - Regex to separate string based on first dot?

我有一列充满了包含多个点的字符串。我想将此列分成两列,包含第一个点前后的两个子字符串。

comb          num
UWEA.n.49.sp   3
KYFZ.n.89.kr   5
     ...

进入

 a         b       num
UWEA    n.49.sp     3
KYFZ    n.89.kr     5
     ...

我正在使用 tidyr 中的 separate 函数,但无法获得正确的正则表达式。我正在尝试使用 this answer:

中的正则表达式样式
foo %>%
    separate(comb, into=c('a', 'b'),
             sep="([^.]+)\.(.*)")

因此第 a 列应由包含至少一个非点字符的第一个捕获组 ([^.]+) 确定,然后是第一个点,然后是第二个捕获组 (.*)只匹配之后剩下的任何内容。

然而,这似乎与任何内容都不匹配:

a   b   num
         3
         5

这是我的虚拟数据集:

library(dplyr)
library(tidyr)
foo <- data.frame(comb=replicate(10, 
                                 paste(paste(sample(LETTERS, 4), collapse=''),
                                       sample(c('p', 'n'), 1), 
                                       sample(1:100, 1), 
                                       paste(sample(letters, 2), collapse=''), 
                                       sep='.')
                                 ),
                  num = sample(1:10, 10, replace=T))

在这种情况下,您可以利用 separate 中的 extra = "merge" 选项。因为 separate 默认在符号上分隔,所以您不必定义分隔符。如果你愿意,你可以使用 "\."

foo %>%
    separate(comb, into=c('a', 'b'), extra = "merge")

      a       b num
1  NPTE p.10.ku   4
2  YAIU p.54.lw   4
3  CHUR n.51.kx   6
4  EPGX n.14.lg   3
5  POBJ n.11.ja   5
6  LEWI n.72.un   7
7  WLAP n.20.ve  10
8  XZUY p.75.cf   6
9  ZSNJ  p.4.aj   3
10 ABKR n.69.ua   3

extra = "merge" 将超出您定义的列的所有额外部分合并到最后一列。

我认为@aosmith 的回答很好,而且绝对没有涉及环视的 regex 解决方案笨拙。但由于您打算使用 regex,这里是:

foo %>% 
    separate(comb, 
             into = c("a","b"), 
             sep = "(?<=[A-Z])\.(?=[a-z]+)")

这里的技巧是正则表达式本身。它使用所谓的 lookaround。基本上,您正在为 sep 参数寻找位于大写字母和小写字母(即 UWEA.n)之间的点 (.)。意思是:match a dot preceded by a capital letter and followed by a lowercase letter.

这允许 separate 函数在 An 之间或 Z 和 [= 之间的点上拆分 comb 列21=],在你的情况下。

希望对您有所帮助。

这里有一个 base R 选项。将 'comb' 列中的第一个 . 替换为 ,,读取 read.csv 以创建基于分隔符 ,cbind 的两列'foo'

的其他列
cbind(read.csv(text=sub("\.", ",", foo$comb), 
          col.names = c('a', 'b'), header=FALSE), foo[-1])
#      a       b num
#1  GJMU n.83.cu   3
#2  IVMD p.85.ny   9
#3  HLQB p.94.rd   8
#4  WIJY n.92.sz   4
#5  QXCM n.38.lf   8
#6  UBNC n.82.js   5
#7  EPLZ n.56.kl   3
#8  YRBA  n.6.ny   8
#9  HQMR p.54.pn  10
#10 LBPO p.98.tv   7

或者另一种选择是使用 tidyr 中的 extract,我们匹配一个或多个不是 . 的字符,将其放在捕获组中(([^.]+) ),后跟一个点 (\.),然后是第二个捕获组 ((.*)) 中的其他字符。捕获的组字符 return 作为两列替换原始 'comb' 列。

library(tidyr)
extract(foo, comb, into = c("a", "b"), "([^.]+)\.(.*)")
#      a       b num
#1  GJMU n.83.cu   3
#2  IVMD p.85.ny   9
#3  HLQB p.94.rd   8
#4  WIJY n.92.sz   4
#5  QXCM n.38.lf   8
#6  UBNC n.82.js   5
#7  EPLZ n.56.kl   3
#8  YRBA  n.6.ny   8
#9  HQMR p.54.pn  10
#10 LBPO p.98.tv   7

注意:OP 的 post

中没有 set.seed