【问题标题】:extract character preceding first dot in a string提取字符串中第一个点之前的字符
【发布时间】:2014-12-11 11:59:16
【问题描述】:

我想提取字符串列中第一个点之前的字符。我可以使用下面的代码来做到这一点。虽然,代码似乎过于复杂,我不得不求助于for-loop。有没有更简单的方法?我对regex 解决方案特别感兴趣。

请注意,查找每个字符串中的最后一个数字不适用于我的真实数据,尽管该方法适用于本示例。

感谢您的建议。

my.data <- read.table(text = '
     my.string  state
     .........    A
     1........    B
     112......    C
     11111....    D
     1111113..    E
     111111111    F
     111111111    G
', header = TRUE, stringsAsFactors = FALSE)

desired.result <- c(NA,1,2,1,3,NA,NA)

确定第一个点的位置:

my.data$first.dot <- apply(my.data, 1, function(x) {     
                                as.numeric(gregexpr("\\.", x['my.string'])[[1]])[1]
                          })

拆分字符串:

split.strings <- t(apply(my.data, 1, function(x) { (strsplit(x['my.string'], '')[[1]]) } ))

my.data$revised.first.dot <- ifelse(my.data$first.dot < 2, NA, my.data$first.dot-1)

提取第一个点之前的字符:

for(i in 1:nrow(my.data)) {
     my.data$character.before.dot[i] <- split.strings[i,my.data$revised.first.dot[i]]
}

my.data

#   my.string state first.dot revised.first.dot character.before.dot
# 1 .........     A         1                NA                 <NA>
# 2 1........     B         2                 1                    1
# 3 112......     C         4                 3                    2
# 4 11111....     D         6                 5                    1
# 5 1111113..     E         8                 7                    3
# 6 111111111     F        -1                NA                 <NA>
# 7 111111111     G        -1                NA                 <NA>

这是一个相关的帖子:

find location of character in string

【问题讨论】:

    标签: regex r string


    【解决方案1】:

    使用下面的正则表达式,不要忘记启用perl=TRUE 参数。

    ^[^.]*?\K[^.](?=\.)
    

    在 R 中,正则表达式就像,

    ^[^.]*?\\K[^.](?=\\.)
    

    DEMO

    > library(stringr)
    > as.numeric(str_extract(my.data$my.string, perl("^[^.]*?\\K[^.](?=\\.)")))
    [1] NA  1  2  1  3 NA NA
    

    模式说明:

    • ^ 断言我们处于起步阶段。
    • [^.]*? 直到第一个点的任何字符的非贪婪匹配。
    • \K 丢弃以前匹配的字符。
    • [^.]我们要匹配的字符不能是点。
    • (?=\.) 而且这个字符后面必须跟一个点。所以它匹配第一个点之前存在的字符。

    【讨论】:

    • 很好,我一直忘记\K
    【解决方案2】:

    最简单的正则表达式是^([^.])+(?=\.):

    ^      # Start of string
    (      # Start of group 1
     [^.]  # Match any character except .
    )+     # Repeat as many times as needed, overwriting the previous match
    (?=\.) # Assert the next character is a .
    

    测试它live on regex101.com

    第 1 组的内容将是您想要的角色。我不是一个 R 人,但根据RegexBuddy,以下应该可以工作:

    matches <- regexpr("^([^.])+(?=\\.)", my.data, perl=TRUE);
    result <- attr(matches, "capture.start")[,1]
    attr(result, "match.length") <- attr(matches, "capture.length")[,1]
    regmatches(my.data, result)
    

    【讨论】:

      【解决方案3】:

      在示例中,都是digits.

      library(stringr)
      as.numeric(str_extract(my.data$my.string, perl('\\d(?=\\.)')))
      #[1] NA  1  2  1  3 NA NA
      

      或者使用stringi

      library(stringi)
      as.numeric(stri_extract(my.data$my.string, regex='\\d(?=\\.)'))
      #[1] NA  1  2  1  3 NA NA
      

      如果是general案例:

      as.numeric(str_extract(my.data$my.string, perl('[^.](?=\\.)')))
      

      【讨论】:

        【解决方案4】:

        这是ifelse 的基本 R 解决方案:

        res <- regexpr("[^.](?=\\.)", my.data$my.string, perl = TRUE)
        ifelse(res < 1, NA, as.integer(regmatches(my.data$my.string, res)))
        # [1] NA  2  1  3  1 NA NA
        

        【讨论】:

          【解决方案5】:
          [^.](?=\\.)
          

          您可以简单地执行此操作。查看演示。

          https://regex101.com/r/qB0jV1/26

          【讨论】:

          • 我没有投反对票,但我在获得desired.result 的任何这些答案时遇到了一些麻烦。在你的情况下,我认为\. 应该是\\.
          • 返回字符的位置。理想情况下,我可以在基础R 中获得向量desired.result。我只需要弄清楚如何做到这一点,我就会做好准备。感谢您的回答。
          • @vks op 没有谈论 unicode 字符串,他提供了他的示例数据。
          • @AvinashRaj 到目前为止,我还没有对这篇文章投赞成票或反对票。一旦我弄清楚如何在基础R 中获取向量desired.result,我可能会投票赞成每个答案。
          【解决方案6】:

          使用rex 可能会使这类任务更简单一些。

          my.data <- read.table(text = '
               my.string  state
               .........    A
               1........    B
               112......    C
               11111....    D
               1111113..    E
               111111111    F
               111111111    G
          ', header = TRUE, stringsAsFactors = FALSE)
          
          library(rex)
          
          re_matches(my.data$my.string,
            rex(capture(except(".")), "."))$'1'
          
          #> [1] NA  "1" "2" "1" "3" NA  NA
          

          【讨论】:

            猜你喜欢
            • 2010-12-28
            • 1970-01-01
            • 1970-01-01
            • 2013-01-21
            • 1970-01-01
            • 1970-01-01
            • 2018-08-21
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多