regex 从字符串中提取前导数字,但长度变化R

nhhxz33t  于 2023-04-22  发布在  其他
关注(0)|答案(2)|浏览(94)

我有一个包含字母和数字的字符串的列。字符串总是以一个或两个数字开头,后面是多个字符。我试图根据第一个字符的位置来分隔字符串。

have <-
  tribble(
    ~string,
    '12main',
    '6six',
    '42go',
    '5to9'
  )

want <- 
  tribble(
    ~prefix, ~rest,
    '12', 'main',
    '6', 'six',
    '42', 'go',
    '5', 'to9'
  )

我相信有一个正则表达式与separate解决方案,但有麻烦让它工作。

want <-
  have %>%
  separate(string,
           into = c('prefix', 'rest'),
           sep = "(?=[0-9])(?<=[a-zA-Z])")
lndjwyie

lndjwyie1#

你已经很接近了,我们可以通过一个look-behind(对于数字)和一个look-ahead(对于非数字)来实现它:

have %>%
  separate(string, sep = "(?<=[0-9])(?=[^0-9])", into = c("prefix", "rest"))
# # A tibble: 4 × 2
#   prefix rest 
#   <chr>  <chr>
# 1 12     main 
# 2 6      six  
# 3 42     go   
# 4 5      to9

我觉得你把事情想反了?<=用于前面的字符串(应与[0-9]一起使用),?=用于后面的字符串(应与[^0-9][A-Za-z]一起使用)。
我个人觉得这有点耐人寻味:我们基于0长度模式拆分字符串:在前一个是数字而后一个是非数字的情况下,两者之间没有任何关系,因此拆分实际上是0长度。
仅供参考,如果字符串中有两个这样的位置,例如5to9to5,则会出现警告:

have <- structure(list(string = c("12main", "6six", "42go", "5to9", "5to9to5")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -5L))
have
# # A tibble: 5 × 1
#   string 
#   <chr>  
# 1 12main 
# 2 6six   
# 3 42go   
# 4 5to9   
# 5 5to9to5
have %>%
  separate(string, sep = "(?<=[0-9])(?=[^0-9])", into = c("prefix", "rest"))
# Warning: Expected 2 pieces. Additional pieces discarded in 1 rows [5].
# # A tibble: 5 × 2
#   prefix rest 
#   <chr>  <chr>
# 1 12     main 
# 2 6      six  
# 3 42     go   
# 4 5      to9  
# 5 5      to9

这是一个警告,你正在丢弃一些信息,如果你想/需要防范这一点,就交给你了。
另一种选择是,因为你的真实的数据中有5to9to5

have %>%
  mutate(strcapture("^([0-9]+)([^0-9].*)", string, list(prefix="", rest="")))
# # A tibble: 5 × 3
#   string  prefix rest  
#   <chr>   <chr>  <chr> 
# 1 12main  12     main  
# 2 6six    6      six   
# 3 42go    42     go    
# 4 5to9    5      to9   
# 5 5to9to5 5      to9to5

如果你想的话,你现在可以删除string
另一个注意事项:如果您打算将prefix转换为整数或数字,则可以通过使用list(prefix=0L, rest="")(或仅使用=0)来排除这种需要。这是proto=参数,虽然它的 data 被丢弃,但它用于每个结果列的名称和目标类。

xyhw6mcr

xyhw6mcr2#

也可以使用extract

have %>%
     extract(string, c('prefix', 'rest'), "(\\d+)(.*)")

# A tibble: 4 × 2
  prefix rest 
  <chr>  <chr>
1 12     main 
2 6      six  
3 42     go   
4 5      to9

相关问题