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
函数在 A
和 n
之间或 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
我有一列充满了包含多个点的字符串。我想将此列分成两列,包含第一个点前后的两个子字符串。
即
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
函数在 A
和 n
之间或 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