【问题标题】:Extract a substring according to a pattern根据模式提取子字符串
【发布时间】:2013-06-17 10:28:52
【问题描述】:

假设我有一个字符串列表:

string = c("G1:E001", "G2:E002", "G3:E003")

现在我希望得到一个字符串向量,它只包含冒号“:”之后的部分,即substring = c(E001,E002,E003)

R 中有没有方便的方法来做到这一点?使用substr?

【问题讨论】:

    标签: regex r substr


    【解决方案1】:

    例如使用gsubsub

        gsub('.*:(.*)','\\1',string)
        [1] "E001" "E002" "E003"
    

    【讨论】:

    • 你能解释一下这些'. * ( * 等等确实在那里吗?我很难在一个稍微不同的设置中重新创建它......
    • @PeterPan 这会捕获并返回出现在冒号之后的字符组。如果要匹配的字符串更复杂,并且您希望保留在基数 R 中,这很有效。
    【解决方案2】:

    这里有几种方法:

    1) 子

    sub(".*:", "", string)
    ## [1] "E001" "E002" "E003"
    

    2) strsplit

    sapply(strsplit(string, ":"), "[", 2)
    ## [1] "E001" "E002" "E003"
    

    3) read.table

    read.table(text = string, sep = ":", as.is = TRUE)$V2
    ## [1] "E001" "E002" "E003"
    

    4) 子字符串

    这假设第二部分总是从第 4 个字符开始(问题示例中就是这种情况):

    substring(string, 4)
    ## [1] "E001" "E002" "E003"
    

    4a) 子字符串/正则表达式

    如果冒号并不总是在已知位置,我们可以通过搜索来修改 (4):

    substring(string, regexpr(":", string) + 1)
    

    5)straplyc

    strapplyc 返回括号部分:

    library(gsubfn)
    strapplyc(string, ":(.*)", simplify = TRUE)
    ## [1] "E001" "E002" "E003"
    

    6) 读取.dcf

    只有在冒号之前的子字符串是唯一的(它们在问题的示例中)时才有效。它还要求分隔符是冒号(这是问题)。如果使用不同的分隔符,那么我们可以先使用sub 将其替换为冒号。例如,如果分隔符是_,那么string <- sub("_", ":", string)

    c(read.dcf(textConnection(string)))
    ## [1] "E001" "E002" "E003"
    

    7) 分开

    7a) 使用tidyr::separate,我们创建了一个包含两列的数据框,一列用于冒号之前的部分,另一列用于冒号之后,然后提取后者。

    library(dplyr)
    library(tidyr)
    library(purrr)
    
    DF <- data.frame(string)
    DF %>% 
      separate(string, into = c("pre", "post")) %>% 
      pull("post")
    ## [1] "E001" "E002" "E003"
    

    7b) 或者,separate 可用于仅创建 post 列,然后 unlistunname 生成数据框:

    library(dplyr)
    library(tidyr)
    
    DF %>% 
      separate(string, into = c(NA, "post")) %>% 
      unlist %>%
      unname
    ## [1] "E001" "E002" "E003"
    

    8) trimws我们可以使用trimws将单词字符从左边剪掉,然后再次使用它来剪掉冒号。

    trimws(trimws(string, "left", "\\w"), "left", ":")
    ## [1] "E001" "E002" "E003"
    

    注意

    输入string 假定为:

    string <- c("G1:E001", "G2:E002", "G3:E003")
    

    【讨论】:

    • 我在一个以_ 作为分隔符的熔化表中有一个变量,并根据@Grothendieck 的答案为前缀和后缀创建了两个单独的变量:prefix &lt;- sub("_.*", "", variable)suffix &lt;- sub(".*_", "", variable)
    • 很高兴看到这个惊人答案的微基准测试!
    【解决方案3】:

    应该这样做:

    gsub("[A-Z][1-9]:", "", string)
    

    给予

    [1] "E001" "E002" "E003"
    

    【讨论】:

      【解决方案4】:

      这是另一个简单的答案

      gsub("^.*:","", string)
      

      【讨论】:

        【解决方案5】:

        晚了,但为了后代,stringr 包(流行的“tidyverse”包套件的一部分)现在提供具有协调签名的字符串处理函数:

        string <- c("G1:E001", "G2:E002", "G3:E003")
        # match string to keep
        stringr::str_extract(string = string, pattern = "E[0-9]+")
        # [1] "E001" "E002" "E003"
        
        # replace leading string with ""
        stringr::str_remove(string = string, pattern = "^.*:")
        # [1] "E001" "E002" "E003"
        

        【讨论】:

        • 这不是找到第一个以 E 开头的数字,而不是冒号后面的所有数字吗?
        【解决方案6】:

        如果您使用的是data.table,那么tstrsplit() 是一个自然的选择:

        tstrsplit(string, ":")[[2]]
        [1] "E001" "E002" "E003"
        

        【讨论】:

          【解决方案7】:

          unglue 包提供了另一种选择,对于简单的情况不需要了解正则表达式,我们会这样做:

          # install.packages("unglue")
          library(unglue)
          string = c("G1:E001", "G2:E002", "G3:E003")
          unglue_vec(string,"{x}:{y}", var = "y")
          #> [1] "E001" "E002" "E003"
          

          reprex package (v0.3.0) 于 2019 年 11 月 6 日创建

          更多信息:https://github.com/moodymudskipper/unglue/blob/master/README.md

          【讨论】:

            【解决方案8】:

            另一种提取子串的方法

            library(stringr)
            substring <- str_extract(string, regex("(?<=:).*"))
            #[1] "E001" "E002" "E003
            
            • (?&lt;=:):看看冒号后面 (:)

            【讨论】:

              【解决方案9】:

              令人惊讶的是,还没有添加一个非常“基本 R”的解决方案:

              string = c("G1:E001", "G2:E002", "G3:E003")
              
              regmatches(string, regexpr('E[0-9]+', string))
              

              【讨论】:

                猜你喜欢
                • 2018-01-14
                • 2021-09-25
                • 1970-01-01
                • 2014-04-22
                • 2020-09-12
                • 1970-01-01
                • 2014-10-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多