【问题标题】:Subset string by counting specific characters通过计算特定字符来子集字符串
【发布时间】:2019-05-25 18:53:33
【问题描述】:

我有以下字符串:

strings <- c("ABBSDGNHNGA", "AABSDGDRY", "AGNAFG", "GGGDSRTYHG") 

我想切断字符串,只要A,G和N的出现次数达到一定值,比如3。那么,结果应该是:

some_function(strings)

c("ABBSDGN", "AABSDG", "AGN", "GGG") 

我尝试使用stringistringr 和正则表达式,但我无法弄清楚。

【问题讨论】:

    标签: r regex gsub stringr stringi


    【解决方案1】:

    您可以通过从 stringr 包中简单地调用 str_extract 来完成您的任务:

    library(stringr)
    
    strings <- c("ABBSDGNHNGA", "AABSDGDRY", "AGNAFG", "GGGDSRTYHG")
    
    str_extract(strings, '([^AGN]*[AGN]){3}')
    # [1] "ABBSDGN" "AABSDG"  "AGN"     "GGG"
    

    正则表达式模式的[^AGN]*[AGN] 部分表示要查找零个或多个非 A、G 或 N 的连续字符,然后是 A、G 或 N 的一个实例。用圆括号和大括号进行附加换行,像这样([^AGN]*[AGN]){3},表示连续查找该模式三遍。您可以通过更改花括号中的整数来更改 A、G、N 的出现次数:

    str_extract(strings, '([^AGN]*[AGN]){4}')
    # [1] "ABBSDGNHN"  NA           "AGNA"       "GGGDSRTYHG"
    

    有几种方法可以使用基本 R 函数来完成您的任务。一种是使用regexpr,后跟regmatches

    m <- regexpr('([^AGN]*[AGN]){3}', strings)
    regmatches(strings, m)
    # [1] "ABBSDGN" "AABSDG"  "AGN"     "GGG"
    

    或者,您可以使用sub

    sub('(([^AGN]*[AGN]){3}).*', '\\1', strings)
    # [1] "ABBSDGN" "AABSDG"  "AGN"     "GGG"
    

    【讨论】:

    • 我不认为它可以比单线 str_extract(strings, '([^AGN]*[AGN]){3}') 更好。不错!
    【解决方案2】:

    这只是 Maurits Evers neat solution 没有 strsplit 的版本。

    sapply(strings,
           function(x) {
             raw <- rawToChar(charToRaw(x), multiple = TRUE)
             idx <- which.max(cumsum(raw %in% c("A", "G", "N")) == 3)
             paste(raw[1:idx], collapse = "")
           })
    ## ABBSDGNHNGA   AABSDGDRY      AGNAFG  GGGDSRTYHG 
    ##   "ABBSDGN"    "AABSDG"       "AGN"       "GGG"
    

    或者,略有不同,没有strsplitpaste

    test <- charToRaw("AGN")
    sapply(strings,
           function(x) {
             raw <- charToRaw(x)
             idx <- which.max(cumsum(raw %in% test) == 3)
             rawToChar(raw[1:idx])
           })
    

    【讨论】:

      【解决方案3】:

      使用gregexpr 识别模式的位置,然后提取第n 个位置(3) 并使用subset 将所有从1 的内容子串到第n 个位置。

      nChars <- 3
      pattern <- "A|G|N"
      # Using sapply to iterate over strings vector
      sapply(strings, function(x) substr(x, 1, gregexpr(pattern, x)[[1]][nChars]))
      

      PS:

      如果有一个字符串没有 3 个匹配,它将生成NA,因此您只需在最终结果上使用na.omit

      【讨论】:

      • 不错! substr 是矢量化的,所以我会像这样简化你的最后一行:substr(strings, 1, map_int(gregexpr(pattern, strings), nChars)),其中使用了来自 purrrmap_int
      【解决方案4】:

      有趣的问题。我创建了一个函数(见下文)来解决您的问题。假设您的任何字符串中只有字母,没有特殊字符。

       reduce_strings = function(str, chars, cnt){
      
        # Replacing chars in str with "!"
        chars = paste0(chars, collapse = "")
        replacement = paste0(rep("!", nchar(chars)), collapse = "")
        str_alias = chartr(chars, replacement, str) 
      
        # Obtain indices with ! for each string
        idx = stringr::str_locate_all(pattern = '!', str_alias)
      
        # Reduce each string in str
        reduce = function(i) substr(str[i], start = 1, stop = idx[[i]][cnt, 1])
        result = vapply(seq_along(str), reduce, "character")
        return(result)
      }
      
      # Example call
      str = c("ABBSDGNHNGA", "AABSDGDRY", "AGNAFG", "GGGDSRTYHG") 
      chars = c("A", "G", "N") # Characters that are counted
      cnt = 3 # Count of the characters, at which the strings are cut off
      reduce_strings(str, chars, cnt) # "ABBSDGN" "AABSDG" "AGN" "GGG"
      

      【讨论】:

        【解决方案5】:

        这是使用strsplit的基本R选项

        sapply(strsplit(strings, ""), function(x)
            paste(x[1:which.max(cumsum(x %in% c("A", "G", "N")) == 3)], collapse = ""))
        #[1] "ABBSDGN" "AABSDG"  "AGN"     "GGG"
        

        或者在tidyverse

        library(tidyverse)
        map_chr(str_split(strings, ""), 
            ~str_c(.x[1:which.max(cumsum(.x %in% c("A", "G", "N")) == 3)], collapse = ""))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-07-23
          • 1970-01-01
          • 2014-01-30
          • 2012-06-07
          • 1970-01-01
          • 2020-11-18
          • 2010-11-20
          • 2023-04-06
          相关资源
          最近更新 更多