【问题标题】:Better Strategy for pulling elements from string从字符串中提取元素的更好策略
【发布时间】:2014-08-06 17:41:32
【问题描述】:

我有一个如下所示的字符串:

x <- "\r\n      Ticker Symbol: RBO\r\n  \t   Exchange: TSX \r\n\t   Assets ($mm) 36.26 \r\n\t   Units Outstanding: 1,800,000 \r\n\t   Mgmt. Fee** 0.25 \r\n      2013 MER* n/a \r\n\t   CUSIP: 74932K103"

我需要的是这个:

list(Ticker = "RBO", Assets = 36.26, Shares = 1,800,000)

我尝试过拆分、正则表达式等。但我觉得我的字符串操作技能达不到标准。

这是迄今为止我的“最佳”尝试。

x <- unlist(strsplit(unlist(strsplit(x, "\r\n\t") ),"\r\n"))
trim <- function (x) gsub("^\\s+|\\s+$", "", x)
x <- trim(x)
gsub("[A-Z]+$","\\2",x[2]) # bad attempt to get RBO

【问题讨论】:

  • 投反对票的人,解释一下你认为我可以做些什么来使这个问题变得更好会很有用。

标签: regex r gsub strsplit


【解决方案1】:

更新/更好的答案:

看看cat(x)readLines(x) 会有很大帮助

> cat(x)
#
#      Ticker Symbol: RBO
#      Exchange: TSX 
#      Assets ($mm) 36.26 #
#      Units Outstanding: 1,800,000 
#      Mgmt. Fee** 0.25 
#      2013 MER* n/a 
#      CUSIP: 74932K103
> readLines(textConnection(x))
# [1] ""                                   "      Ticker Symbol: RBO"          
# [3] "  \t   Exchange: TSX "              "\t   Assets ($mm) 36.26 "          
# [5] "\t   Units Outstanding: 1,800,000 " "\t   Mgmt. Fee** 0.25 "            
# [7] "      2013 MER* n/a "               "\t   CUSIP: 74932K103"

现在我们知道了一些事情。第一,我们不需要第一行,而我们确实想要第二行。这使事情变得更容易,因为现在第一行与我们想要的第一行匹配。接下来,您的列表名称与字符串中的名称匹配会更容易。我选择了这些。

> nm <- c("Symbol", "Assets", "Units")

现在我们所要做的就是使用grepsapply,我们将返回一个命名的匹配向量。在grep 中设置value = TRUE 将返回字符串。

> (y <- sapply(nm, grep, x = readLines(textConnection(x))[-1], value = TRUE))
# b                              Symbol                               Assets 
#           "      Ticker Symbol: RBO"           "\t   Assets ($mm) 36.26 " 
#                                Units 
# "\t   Units Outstanding: 1,800,000 " 

然后我们在"[: ]"strsplit,获取每个拆分中的最后一个元素,我们就完成了。

> lapply(strsplit(y, "[: ]"), tail, 1)
$Symbol
[1] "RBO"

$Assets
[1] "36.26"

$Units
[1] "1,800,000

您可以使用

获得相同的结果
> g <- gsub("[[:cntrl:]]", "", capture.output(cat(x))[-1])
> m <- mapply(grep, nm, MoreArgs = list(x = g, value = TRUE))
> lapply(strsplit(m, "[: ]"), tail, 1)

希望对您有所帮助。


原答案:

看起来如果你从一张大桌子上拉出这些,它们每次都会在同一个元素“槽”中,所以也许这会更容易一些。

> s <- strsplit(x, "[: ]|[[:cntrl:]]")[[1]]

解释:
- [: ] 匹配 ":" 字符后跟空格字符
- |
- [[:cntrl:]] 任何控制字符,在本例中是\r\t\n 中的任何一个。这可能更好地解释here

然后,nzchar 在上述结果中查找非零长度字符串,如果匹配则返回 TRUE,否则返回 FALSE。因此,我们可以查看第一行的结果,确定匹配的位置,并据此确定子集。

> as.list(s[nzchar(s)][c(3, 8, 11)])
[[1]]
[1] "RBO"

[[2]]
[1] "36.26"

[[3]]
[1] "1,800,000"

您可以通过将 s 指定为内部调用将 is 放入一行。由于函数和调用是从内向外评估的,因此在 R 到达外部 s 子集之前分配了 s。不过,这有点可读性差。

s[nzchar(s <- strsplit(x, "[: ]|[[:cntrl:]]")[[1]])][c(3,8,11)]

所以这将是s &lt;- strsplit(...) -> [[ -> nzchar -> s[.. >- [c(3,8,11)]

【讨论】:

  • 这很有趣。介意解释一下吗?
  • @BrandonBertelsen - 我添加了解释。希望它有所帮助。
  • @BrandonBertelsen - 我还添加了一个更好的方法。
  • 很简单,感谢解释。
【解决方案2】:

也许:

 sub( "\\\r\\\n.+$", "", sub( "^.+Ticker Symbol: ", "", x) )
[1] "RBO"

我想你可以在一个带括号的模式中完成所有操作。和反向引用。

> sub( "^.+Ticker Symbol: ([[:alpha:]]{1,})\\\r\\\n.+$", "\\1", x)
[1] "RBO"

【讨论】:

    【解决方案3】:

    如果只是想提取字符串的不同部分,可以使用regexpr查找词组,提取词组后面的内容。例如

    extr<-list(
        "Ticker" = "Ticker Symbol: ",
        "Assets" = "Assets ($mm) ",
        "Shares" = "Units Outstanding: "
    )
    
    lines<-strsplit(x,"\r\n")[[1]]
    
    Map(function(p) {
        m <- regexpr(p, lines, fixed=TRUE)
        if(length( w<- which(m!=-1))==1) {
            gsub("^\\sw+|\\s$", "",
                substr(lines[w], m[w] + attr(m,"match.length")[w], nchar(lines[w])))
        } else {
            NA
        }
    }, extr)
    

    根据需要返回命名列表

    $Ticker
    [1] "RBO"
    
    $Assets
    [1] "36.26"
    
    $Shares
    [1] "1,800,000"
    

    这里extr 是一个列表,其中元素的名称是最终列表中将使用的名称,元素值是文本中将匹配的确切字符串。我还添加了gsub 以删除任何空白。

    【讨论】:

      【解决方案4】:

      stringr 包非常适合从字符串中抓取数据。这是我每次使用的步骤。您始终可以将规则设置为您认为合适的具体或稳健的规则。

      require(stringr)
      
      ## take out annoying characters
      x <- gsub("\r\n", "", x)
      x <- gsub("\t", "", x)
      x <- gsub("\\(\\$mm\\) ", "", x)
      
      ## define character index positions of interest
      tickerEnd <- str_locate(x, "Ticker Symbol: ")[[1, "end"]]
      assetsEnd <- str_locate(x, "Assets ")[[1, "end"]]
      unitsStart <- str_locate(x, "Units Outstanding: ")[[1, "start"]]
      unitsEnd <- str_locate(x, "Units Outstanding: ")[[1, "end"]]
      mgmtStart <- str_locate(x, "Mgmt")[[1, "start"]]
      
      ## get substrings based on indices
      tickerTxt <- substr(x, tickerEnd + 1, tickerEnd + 4) # allows 4-character symbols
      assetsTxt <- substr(x, assetsEnd + 1, unitsStart - 1)
      sharesTxt <- substr(x, unitsEnd + 1, mgmtStart - 1)
      
      ## cut out extraneous characters
      ticker <- gsub(" ", "", tickerTxt)
      assets <- gsub(" ", "", assetsTxt)
      shares <- gsub(" |,", "", sharesTxt)
      
      ## add data to data frame
      df <- data.frame(ticker, as.numeric(assets), as.numeric(shares), stringsAsFactors = FALSE)
      

      【讨论】:

        猜你喜欢
        • 2019-03-04
        • 2013-12-10
        • 2018-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-18
        • 1970-01-01
        相关资源
        最近更新 更多