【问题标题】:Extract a regular expression match提取正则表达式匹配
【发布时间】:2011-01-12 15:13:39
【问题描述】:

我正在尝试从字符串中提取一个数字。

然后在字符串"aaa12xxx" 上执行类似[0-9]+ 的操作,然后得到"12"

我以为会是这样的:

> grep("[0-9]+", "aaa12xxx", value=TRUE)
[1] "aaa12xxx"

然后我想...

> sub("[0-9]+", "\\1", "aaa12xxx")
[1] "aaaxxx"

但我得到了某种形式的回应:

> sub("[0-9]+", "ARGH!", "aaa12xxx")
[1] "aaaARGH!xxx"

我遗漏了一个小细节。

【问题讨论】:

    标签: regex r


    【解决方案1】:

    使用新的 stringr 包,它包装了所有现有的正则表达式,以一致的语法运行,并添加了一些缺失的内容:

    library(stringr)
    str_locate("aaa12xxx", "[0-9]+")
    #      start end
    # [1,]     4   5
    str_extract("aaa12xxx", "[0-9]+")
    # [1] "12"
    

    【讨论】:

    • (几乎)正是我所需要的,但当我开始输入?str_extract 时,我看到了str_extract_all,生活又美好了。
    【解决方案2】:

    说“忽略标准函数”可能有点草率——?gsub 的帮助文件甚至在“另见”中特别提到:

    ‘regmatches’用于根据结果提取匹配的子字符串 “regexpr”、“gregexpr”和“regexec”。

    所以这会起作用,而且相当简单:

    txt <- "aaa12xxx"
    regmatches(txt,regexpr("[0-9]+",txt))
    #[1] "12"
    

    【讨论】:

    • 如何提取多个组?例如,从字符串“aaa12bbb15ccc”中分别提取12和15?
    • @DuccioA - regmatches(x, gregexpr("[0-9]+", x)) - like sub 代表一个替换,gsub 代表所有替换,regexpr 找到一个结果,而gregexpr 找到所有结果。跨度>
    【解决方案3】:

    对于您的具体情况,您可以删除所有非数字:

    gsub("[^0-9]", "", "aaa12xxxx")
    # [1] "12"
    

    它不适用于更复杂的情况

    gsub("[^0-9]", "", "aaa12xxxx34")
    # [1] "1234"
    

    【讨论】:

    • 不是从字符串中提取目标的最佳选择。这对于仅返回字符串中可能会或可能不会在一起的任何数字很有用,方法是删除所有不是数字的字符,如果您认为它提取了可能会造成未命中的字符(例如,gsub("[^0-9]", " ", "aaa12xx1xx" 返回 121 而不是预期的 c(12, 1))
    • @daneshjai 这正是 OP 想要的。这不是广义的解决方案。
    • 不一定。问题的标题是“提取正则表达式匹配”。它适合这个例子,但它可能会给人错误的印象,在某些情况下会产生相反的结果。所以我认为这有助于其他最终登陆这里并且可能是正则表达式的新手来澄清这是删除所有字符而不是提取目标的模式。
    • @daneshjai 大多数答案为“aaa12xx1xx”返回 12,这不是您所期望的。
    【解决方案4】:

    您可以使用 PERL 正则表达式的惰性匹配:

    > sub(".*?([0-9]+).*", "\\1", "aaa12xx99",perl=TRUE)
    [1] "12"
    

    在这种情况下,尝试替换非数字会导致错误。

    【讨论】:

    • 如果你愿意使用稍微丑一点的“[^0-9]*([0-9]+).*”就不需要PERL
    【解决方案5】:

    在正则表达式中使用捕获括号并在替换中使用组引用。括号中的任何内容都会被记住。然后它们被第一项 \2 访问。第一个反斜杠在 R 中转义了反斜杠的解释,以便将其传递给正则表达式解析器。

    gsub('([[:alpha:]]+)([0-9]+)([[:alpha:]]+)', '\\2', "aaa12xxx")
    

    【讨论】:

      【解决方案6】:

      一种方法是这样的:

      test <- regexpr("[0-9]+","aaa12456xxx")
      

      现在,请注意 regexpr 为您提供字符串的开始和结束索引:

          > test
      [1] 4
      attr(,"match.length")
      [1] 5
      

      所以你可以将这些信息与 substr 函数一起使用

      substr("aaa12456xxx",test,test+attr(test,"match.length")-1)
      

      我确信有一种更优雅的方法可以做到这一点,但这是我能找到的最快的方法。或者,您可以使用 sub/gsub 删除您不想留下的东西,留下您想要的东西。

      【讨论】:

        【解决方案7】:

        这些方法之间的一个重要区别是任何不匹配的行为。例如,如果不是所有位置都匹配,则 regmatches 方法可能不会返回与输入长度相同的字符串

        > txt <- c("aaa12xxx","xyz")
        
        > regmatches(txt,regexpr("[0-9]+",txt)) # could cause problems
        
        [1] "12"
        
        > gsub("[^0-9]", "", txt)
        
        [1] "12" ""  
        
        > str_extract(txt, "[0-9]+")
        
        [1] "12" NA  
        

        【讨论】:

          【解决方案8】:

          这个问题的解决方案

          library(stringr)
          str_extract_all("aaa12xxx", regex("[[:digit:]]{1,}"))
          # [[1]]
          # [1] "12"
          

          [[:digit:]]:数字[0-9]

          {1,}:至少匹配 1 次

          【讨论】:

            【解决方案9】:

            在 gsubfn 包中使用 strapply。 strapply 和 apply 一样,args 是对象、修饰符和函数,只是对象是字符串向量(而不是数组),修饰符是正则表达式(而不是边距):

            library(gsubfn)
            x <- c("xy13", "ab 12 cd 34 xy")
            strapply(x, "\\d+", as.numeric)
            # list(13, c(12, 34))
            

            这表示匹配 x 的每个组件中的一个或多个数字 (\d+),通过 as.numeric 传递每个匹配项。它返回一个列表,其分量是 x 的各个分量的匹配向量。查看 at 输出,我们看到 x 的第一个分量有一个匹配项,即 13,而 x 的第二个分量有两个匹配项,即 12 和 34。有关详细信息,请参阅 http://gsubfn.googlecode.com

            【讨论】:

              【解决方案10】:

              另一种解决方案:

              temp = regexpr('\\d', "aaa12xxx");
              substr("aaa12xxx", temp[1], temp[1]+attr(temp,"match.length")[1])
              

              【讨论】:

                【解决方案11】:

                使用包 unglue 我们将执行以下操作:

                # install.packages("unglue")
                library(unglue)
                unglue_vec(c("aaa12xxx", "aaaARGH!xxx"), "{prefix}{number=\\d+}{suffix}", var = "number")
                #> [1] "12" NA
                

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

                使用convert 参数自动转换为数字:

                unglue_vec(
                  c("aaa12xxx", "aaaARGH!xxx"), 
                  "{prefix}{number=\\d+}{suffix}", 
                  var = "number", 
                  convert = TRUE)
                #> [1] 12 NA
                

                【讨论】:

                  【解决方案12】:

                  您可以使用 C++ 编写正则表达式函数,将它们编译成 DLL 并从 R 中调用它们。

                      #include <regex>
                  
                      extern "C" {
                      __declspec(dllexport)
                      void regex_match( const char **first, char **regexStr, int *_bool)
                      {
                          std::cmatch _cmatch;
                          const char *last = *first + strlen(*first);
                          std::regex rx(*regexStr);
                          bool found = false;
                          found = std::regex_match(*first,last,_cmatch, rx);
                          *_bool = found;
                      }
                  
                  __declspec(dllexport)
                  void regex_search_results( const char **str, const char **regexStr, int *N, char **out )
                  {
                      std::string s(*str);
                      std::regex rgx(*regexStr);
                      std::smatch m;
                  
                      int i=0;
                      while(std::regex_search(s,m,rgx) && i < *N) {
                          strcpy(out[i],m[0].str().c_str());
                          i++;
                          s = m.suffix().str();
                      }
                  }
                      };
                  

                  在 R 中调用为

                  dyn.load("C:\\YourPath\\RegTest.dll")
                  regex_match <- function(str,regstr) {
                  .C("regex_match",x=as.character(str),y=as.character(regstr),z=as.logical(1))$z }
                  
                  regex_match("abc","a(b)c")
                  
                  regex_search_results <- function(x,y,n) {
                  .C("regex_search_results",x=as.character(x),y=as.character(y),i=as.integer(n),z=character(n))$z }
                  
                  regex_search_results("aaa12aa34xxx", "[0-9]+", 5)
                  

                  【讨论】:

                  • 这完全没有必要。请参阅“thelatemail”或“Robert”的答案以获得 R 中的简单解决方案。
                  猜你喜欢
                  • 1970-01-01
                  • 2015-03-08
                  • 1970-01-01
                  • 2013-02-02
                  • 1970-01-01
                  相关资源
                  最近更新 更多