R-查找和;从右边提取字符串

R-查找和;从右边提取字符串,r,tidyverse,R,Tidyverse,我有这个向量: data <- structure(1:5, .Label = c("AVE_prQD_AFR_p10", "PER_prVD_DSR_p9", "PA_prSX_AR_p8", "prAV_AES_p7", "prGR_AXXR_p6", "prQW_AWAR_p5"), class = "factor") V1 1 &quo

我有这个向量:

data <- structure(1:5, .Label = c("AVE_prQD_AFR_p10", "PER_prVD_DSR_p9", "PA_prSX_AR_p8", 
"prAV_AES_p7", "prGR_AXXR_p6", "prQW_AWAR_p5"), class = "factor")

  V1
1 "AVE_prQD_AFR_p10"
2 "PER_prVD_DSR_p9"
3 "PA_prS_X_AR_p8"
4 "prAV_AES_p7"
5 "prGR_AXXR_p6"
从上面的示例可以推断,字符串的最后一部分将始终以
\uu
开头,然后是
p
f
0
,然后以1到99之间的数字结束字符串(0除外):

数字后面永远不会有任何东西。因此,整个字符串以我需要的字符串结尾。因此,我正在寻找一个解决方案,试图从右侧搜索
,但未成功

另外,我需要在以下条件下转换该字符串:

  • 如果字符串有
    p
    ,则将该数字乘以
    -1
  • 如果字符串有
    f
    ,则数字为正数
  • 如果字符串是
    \u 0
    ,则将其指定为
    0
这是我的尝试,它可以工作,但只能在固定位置
\uuu
和数字0到9的情况下工作

function(some_vector_string){
  result <- stringr::str_sub(some_vector_string, -2,-2) %>% 
    {ifelse(. == "p",
            as.numeric(stringr::str_sub(some_vector_string, -1,-1))*-1,
            ifelse(. == "f",
                   as.numeric(stringr::str_sub(some_vector_string, -1,-1))*1,
                   ifelse(.=="_", 0, -100)))}
  return(result)
}
函数(一些向量字符串){
结果%
{ifelse(.==“p”,
as.numeric(stringr::str_sub(某些向量_字符串,-1,-1))*-1,
ifelse(.=“f”,
as.numeric(stringr::str_sub(某些向量_字符串,-1,-1))*1,
ifelse(.==”,0,-100))}
返回(结果)
}

我尝试使用REBS,结果如下:

library(tidyverse)
library(rebus)
library(stringr)
data <- structure(1:5, .Label = c("AVE_prQD_AFR_p10", "PER_prVD_DSR_p9", "PA_prSX_AR_p8", 
                                      "prAV_AES_p7", "prGR_AXXR_p6", "prQW_AWAR_p5"), class = "factor")
    
#rebus END regex lets you narrow the search to the last part of the string
chars <-
    str_extract(data , rebus::or(ANY_CHAR %R% one_or_more(DGT) %R% END, '0' %R% END)) 
    
    ##fabricate the conditions
    #map_dbl is also an option to avoid returning a list
numbers <-
    map(chars, ~
            if(str_sub(.x,1 ,1) == 'p'){
                as.numeric(str_extract(.x, one_or_more(DGT))) * -1
            } else{
                if (str_sub(.x,1 ,1) == 'f'){
                    as.numeric(str_extract(.x, one_or_more(DGT)))
                } else {
                    0
                }
                
        })
    
print(numbers)
``
库(tidyverse)
图书馆(REBS)
图书馆(stringr)

数据我尝试了REBS,结果如下:

library(tidyverse)
library(rebus)
library(stringr)
data <- structure(1:5, .Label = c("AVE_prQD_AFR_p10", "PER_prVD_DSR_p9", "PA_prSX_AR_p8", 
                                      "prAV_AES_p7", "prGR_AXXR_p6", "prQW_AWAR_p5"), class = "factor")
    
#rebus END regex lets you narrow the search to the last part of the string
chars <-
    str_extract(data , rebus::or(ANY_CHAR %R% one_or_more(DGT) %R% END, '0' %R% END)) 
    
    ##fabricate the conditions
    #map_dbl is also an option to avoid returning a list
numbers <-
    map(chars, ~
            if(str_sub(.x,1 ,1) == 'p'){
                as.numeric(str_extract(.x, one_or_more(DGT))) * -1
            } else{
                if (str_sub(.x,1 ,1) == 'f'){
                    as.numeric(str_extract(.x, one_or_more(DGT)))
                } else {
                    0
                }
                
        })
    
print(numbers)
``
库(tidyverse)
图书馆(REBS)
图书馆(stringr)

数据在base
R
中,类似于:

a <- sapply(strsplit(as.character(data), "_"), function(x) rev(x)[1])

ifelse(startsWith(a, "0"), 0, c(-1, 1)[startsWith("p", a) + 1] * as.numeric(gsub("\\D*", "", a)))
[1] -10  -9  -8  -7  -6
这与ungreedy(
)相反,ungreedy不尝试尽可能匹配:

str_remove("A_B_C_D", ".*?_")
[1] "B_C_D"
  • purrr::map\u dbl
  • 此函数迭代列表或原子向量,并输出double类型的原子向量,因此为
    \u dbl

    ~
    是一种lambda/purrr风格的语法。在
    R
    4.1.0之前,它都是用base
    R
    编写的:
    function(x)n[substr(x,1,1)]*parse_number(x)
    。它只是一种更简洁、更容易阅读、不太冗长的匿名函数应用方式(即未指定名称的函数)。这是tidyverse中常见的语法样式。此处,函数的
    x
    参数被点符号
    替换

  • n[substr(,1,1)]*解析编号(。
  • substr(,1,1)
    获取解析字符串的第一个字符:

    substr("f20", 1,1 )
    [1] "f"
    
    然后它查找命名向量
    n
    中的第一个字符,以返回您在问题中指定的值,当字母为
    “f”
    时,该值为:

    readr::parse_number
    从字符串中提取所有数字并将其作为数字返回:

    readr::parse_number("f20")
    [1] 20
    
    这两个值相乘,并作为双原子向量输出中的元素返回

    注意:当后缀为
    “0”
    时,此操作有效,因为此操作的结果为
    0*0

    substr("0",1 ,1)
    [1] "0"
    
    n["0"]
    0 
    0 
    
    parse_number("0")
    [1] 0
    
    n[substr("0", 1, 1)] * parse_number("0")
    0 
    0 
    

    您会注意到,从技术上讲,此输出是一个命名向量,名称为
    “0”
    ,值为
    0
    ;但是,这是由base
    R
    中的
    map\u dbl
    强制为双向量的,类似于:

    a <- sapply(strsplit(as.character(data), "_"), function(x) rev(x)[1])
    
    ifelse(startsWith(a, "0"), 0, c(-1, 1)[startsWith("p", a) + 1] * as.numeric(gsub("\\D*", "", a)))
    [1] -10  -9  -8  -7  -6
    
    这与ungreedy(
    )相反,ungreedy不尝试尽可能匹配:

    str_remove("A_B_C_D", ".*?_")
    [1] "B_C_D"
    
  • purrr::map\u dbl
  • 此函数迭代列表或原子向量,并输出double类型的原子向量,因此为
    \u dbl

    ~
    是一种lambda/purrr风格的语法。在
    R
    4.1.0之前,它都是用base
    R
    编写的:
    function(x)n[substr(x,1,1)]*parse_number(x)
    。它只是一种更简洁、更容易阅读、不太冗长的匿名函数应用方式(即未指定名称的函数)。这是tidyverse中常见的语法样式。此处,函数的
    x
    参数被点符号
    替换

  • n[substr(,1,1)]*解析编号(。
  • substr(,1,1)
    获取解析字符串的第一个字符:

    substr("f20", 1,1 )
    [1] "f"
    
    然后它查找命名向量
    n
    中的第一个字符,以返回您在问题中指定的值,当字母为
    “f”
    时,该值为:

    readr::parse_number
    从字符串中提取所有数字并将其作为数字返回:

    readr::parse_number("f20")
    [1] 20
    
    这两个值相乘,并作为双原子向量输出中的元素返回

    注意:当后缀为
    “0”
    时,此操作有效,因为此操作的结果为
    0*0

    substr("0",1 ,1)
    [1] "0"
    
    n["0"]
    0 
    0 
    
    parse_number("0")
    [1] 0
    
    n[substr("0", 1, 1)] * parse_number("0")
    0 
    0 
    
    您会注意到,从技术上讲,此输出是一个命名向量,名称为
    “0”
    ,值为
    0
    ;但是,这是由
    map\u dbl

    数据强制为双向量的:

    data <- data.frame(V1 = c("AVE_prQD_AFR_p10", "PER_prVD_DSR_p9", "PA_prSX_AR_p8", 
                         "prAV_AES_p7", "prGR_AXXR_p6", "prQW_AWAR_p5",
                         "AVE_prQD_AFR_f10", "PER_prVD_DSR_f9", "PA_prSX_AR_f8", 
                         "prAV_AES_f7", "prGR_AXXR_f6", "prQW_AWAR_f5",
                         "AVE_prQD_AFR_0", "PER_prVD_DSR_0", "PA_prSX_AR_0", 
                         "prAV_AES_0", "prGR_AXXR_0", "prQW_AWAR_0"))
    
    data %>% 
      tidyr::extract(V1, c("V2", "V3"), "([[:alnum:]_]+)_([[:alnum:]]+)$", remove = FALSE) %>% 
      mutate(V4 = readr::parse_number(V3),
             v5 = case_when(stringr::str_detect(V3, "p") ~ V4*-1,
                            TRUE ~ V4))
    
    方法2

    或者,与将字符串拆分为2(如方法1所示)不同,我们可以只提取感兴趣的部分并从中开始工作

    data %>% 
      mutate(V2 = stringr::str_extract(V1, "[pf]?\\d{1,2}$"),
             V3 = readr::parse_number(V2),
             v4 = case_when(stringr::str_detect(V2, "p") ~ V3*-1,
                            TRUE ~ V3))
    
    数据

    data <- data.frame(V1 = c("AVE_prQD_AFR_p10", "PER_prVD_DSR_p9", "PA_prSX_AR_p8", 
                         "prAV_AES_p7", "prGR_AXXR_p6", "prQW_AWAR_p5",
                         "AVE_prQD_AFR_f10", "PER_prVD_DSR_f9", "PA_prSX_AR_f8", 
                         "prAV_AES_f7", "prGR_AXXR_f6", "prQW_AWAR_f5",
                         "AVE_prQD_AFR_0", "PER_prVD_DSR_0", "PA_prSX_AR_0", 
                         "prAV_AES_0", "prGR_AXXR_0", "prQW_AWAR_0"))
    
    data %>% 
      tidyr::extract(V1, c("V2", "V3"), "([[:alnum:]_]+)_([[:alnum:]]+)$", remove = FALSE) %>% 
      mutate(V4 = readr::parse_number(V3),
             v5 = case_when(stringr::str_detect(V3, "p") ~ V4*-1,
                            TRUE ~ V4))
    
    方法2

    或者,与将字符串拆分为2(如方法1所示)不同,我们可以只提取感兴趣的部分并从中开始工作

    data %>% 
      mutate(V2 = stringr::str_extract(V1, "[pf]?\\d{1,2}$"),
             V3 = readr::parse_number(V2),
             v4 = case_when(stringr::str_detect(V2, "p") ~ V3*-1,
                            TRUE ~ V3))
    

    提取所有结束数字并与-1相乘的解决方案,如果它们以f开头(正数无论如何都可以,0没有符号):

    库(tidyverse)
    数据%
    enframe(name=NULL,value=“V1”)%%>%#从矢量创建可编辑文件
    mutate(want=as.numeric(str_extract(V1,\\d+$))))*if_else(str_detect(V1,\\f\\d+$)-1))
    #想要
    #            
    #1 AVE_prQD_AFR_p10 10
    #每件2件9件
    #第3页第8页
    #4 prAV_AES_p7 7
    #5 prGR_AXXR_p6 6
    #6 prQW_AWAR_p5 5
    #7 prQW_AWAR_0 0
    #8 prQW_AWAR_f5-5
    
    提取所有结尾数字并与-1相乘的解决方案,如果它们以f(正数)开头