【问题标题】:regex grab from beginning to n occurrence of character正则表达式从开始到 n 次出现字符
【发布时间】:2013-04-09 18:24:36
【问题描述】:

我真的把时间花在学习正则表达式上,而且我正在玩不同的玩具场景。我无法使用的一种设置是从字符串的开头抓取到 n 个字符,其中 n > 1。

这里我可以从字符串的开头抓取到第一个下划线,但我不能将它概括为第二个或第三个下划线。

x <- c("a_b_c_d", "1_2_3_4", "<_?_._:")

gsub("_.*$", "", x)

Here's what I'm trying to achieve with regex. (`sub`/`gsub`):

## > sapply(lapply(strsplit(x, "_"), "[", 1:2), paste, collapse="_")
## [1] "a_b" "1_2" "<_?"

#or

## > sapply(lapply(strsplit(x, "_"), "[", 1:3), paste, collapse="_")
## [1] "a_b_c" "1_2_3" "<_?_."

相关帖子:regex from first character to the end of the string

【问题讨论】:

    标签: regex r


    【解决方案1】:

    这是一个开始。为使其安全以供一般使用,您需要正确转义正则表达式的特殊字符:

    x <- c("a_b_c_d", "1_2_3_4", "<_?_._:", "", "abcd", "____abcd")
    
    matchToNth <- function(char, n) {
        others <- paste0("[^", char, "]*") ## matches "[^_]*" if char is "_"
        mainPat <- paste0(c(rep(c(others, char), n-1), others), collapse="")
        paste0("(^", mainPat, ")", "(.*$)")
    }
    
    gsub(matchToNth("_", 2), "\\1", x)
    # [1] "a_b"  "1_2"  "<_?"  ""     "abcd" "_" 
    
    gsub(matchToNth("_", 3), "\\1", x)
    # [1] "a_b_c" "1_2_3" "<_?_." ""      "abcd"  "__"   
    

    【讨论】:

    • 我实际上正在做类似的事情。我的方法很接近,但与您的方法不同。安全方法的好调用,我在 qdap 中使用它; library(qdap); genX
    • @TylerRinker -- 请注意,您接受的答案不适用于以下字符串:x &lt;- c("_a_b", "a__b")
    【解决方案2】:

    怎么样:

    gsub('^(.+_.+?).*$', '\\1', x)
    # [1] "a_b" "1_2" "<_?"
    

    您也可以使用{} 来指示重复次数...

    sub('((.+_){1}.+?).*$', '\\1', x)  # {0} will give "a", {1} - "a_b", {2} - "a_b_c" and so on
    

    所以如果你想匹配第n个,你不必重复自己......

    【讨论】:

    • 第二个正则表达式缺少.+?,应该是sub('((.+_){2}.+?).*$', '\\1', x)
    • @eddi 第二个正则表达式没有丢失它,因为我不知道如何使它正常工作!我认为它会更接近我的编辑。感谢您为我指明正确的方向。
    • ? 之前没有.+,最后你会得到一个额外的_,这似乎与OP 的示例不匹配
    • 没错,但你也得到了 3 个字符 :) 第二个字符只是在黑暗中拍摄,我知道它不起作用。随意修复它!
    • @eddi 由于建议的编辑审核系统缺乏上下文,您的建议编辑已被拒绝 (+2-3),因此我已直接应用您的编辑重新编辑了答案。如果有兴趣,您可以在 Meta 上查看我正在进行的主题,以获取建议的编辑审核队列改进。
    【解决方案3】:

    perl 风格正则表达式中的第二个下划线:

    /^(.?_.?_)/
    

    第三个:

    /^(.*?_.*?_.*?_)/
    

    【讨论】:

      【解决方案4】:

      可能是这样的

      x
      ## [1] "a_b_c_d" "1_2_3_4" "<_?_._:"
      
      gsub("(.*)_", "\\1", regmatches(x, regexpr("([^_]*_){1}", x)))
      ## [1] "a" "1" "<"
      
      gsub("(.*)_", "\\1", regmatches(x, regexpr("([^_]*_){2}", x)))
      ## [1] "a_b" "1_2" "<_?"
      
      gsub("(.*)_", "\\1", regmatches(x, regexpr("([^_]*_){3}", x)))
      ## [1] "a_b_c" "1_2_3" "<_?_."
      

      【讨论】:

        【解决方案5】:

        使用贾斯汀的方法,这是我设计的:

        beg2char <- function(text, char = " ", noc = 1, include = FALSE) {
            inc <- ifelse(include, char, "?")
            specchar <- c(".", "|", "(", ")", "[", "{", "^", "$", "*", "+", "?")
            if(char %in% specchar) {
                char <- paste0("\\", char)
            }
            ins <- paste(rep(paste0(char, ".+"), noc - 1), collapse="")
            rep <- paste0("^(.+", ins, inc, ").*$")
            gsub(rep, "\\1", text)
        }
        
        x <- c("a_b_c_d", "1_2_3_4", "<_?_._:")
        beg2char(x, "_", 1)
        beg2char(x, "_", 2)
        beg2char(x, "_", 3)
        beg2char(x, "_", 4)
        beg2char(x, "_", 3, include=TRUE)
        

        【讨论】:

        • 这些结果真的是您想要的吗? x &lt;- "a____b"; beg2char(x, "_", 2); beg2char(x, "_", 1)
        • @JoshO'Brien 我想是的,但也许你看到一个角落案例或其他什么我不知道你具体在想什么?
        • 哦,我看到您在上面的评论。是的,就我的目的而言,但我认为对其他人来说,你的方法就是他们所追求的。
        • 很公平。我想我只是不太了解您实际上在追求什么行为,或者至少不知道您希望它在哪个输入域上工作。 (不是我要求进一步澄清。)干杯。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多