【问题标题】:Pull out text before phrase - Regex R在短语之前提取文本 - 正则表达式 R
【发布时间】:2021-02-16 10:20:31
【问题描述】:

我希望在R 中使用正则表达式提取出现在一组短语之前的文本。

示例短语c("PHRASE1", "PHRASE2", "PHRASE3")

示例文本:

*NAME ALPHA PHRASE1 BLA BLA TEXT 81249
*NAME BETA PHRASE1 BLA BLA 81229
*NAME GAMMA PHRASE2 BLA BLA TEXT 85129
*NAME DELTA PHRASE3 BLA BLA 86129
*NAME EPSILON PHRASE2 BLA BLA 81729

我想拉出下面的c("NAME ALPHA", "NAME BETA", "NAME GAMMA")等等(忽略*)。

正则表达式 101 链接:https://regex101.com/r/Fzinr8/1

初步尝试

(!\*)q+(?=PHRASE1)

R:

str_extract(x, "(!\*)q+(?=PHRASE1)")

【问题讨论】:

  • 您的模式中的q 是什么? !\* 匹配 !* 字符串,你的字符串中没有它。请注意,您需要在常规字符串文字中使用双反斜杠来定义文字反斜杠(正则表达式转义部分)
  • 对不起,我对正则表达式很陌生
  • 但是你知道q 匹配q 字符吗?你什么意思?在* 之后开始尽可能少地匹配任何类型的字符?还是空格分隔的单词序列?
  • 我试图在PHRASE1开始之前提取所有字符,所以我想要所有字符q所以我把+
  • 试试这个正则表达式:(?<=\*).*?(?=\s(?:PHRASE1|PHRASE2|PHRASE3))

标签: r regex stringr


【解决方案1】:

将我的评论转换为答案,以便将来的访问者轻松找到解决方案。

您可以通过后向和前瞻来使用此正则表达式:

str_extract(x, '(?<=\\*).*?(?=\\s(?:PHRASE1|PHRASE2|PHRASE3))');

RegEx Demo

正则表达式详细信息:

  • (?&lt;=\\*):断言我们在之前的位置有一个*
  • .*?:匹配 0 个或多个任意字符(惰性匹配)
  • (?=\\s(?:PHRASE1|PHRASE2|PHRASE3)):正向前瞻断言我们在当前位置前面有一个空格,后跟(?:PHRASE1|PHRASE2|PHRASE3)

【讨论】:

    【解决方案2】:

    stringr 解决方案

    你可以使用

    x<-c("*NAME ALPHA PHRASE1 BLA BLA TEXT 81249","*NAME BETA PHRASE1 BLA BLA 81229","*NAME GAMMA PHRASE2 BLA BLA TEXT 85129","*NAME DELTA PHRASE3 BLA BLA 86129","*NAME EPSILON PHRASE2 BLA BLA 81729")
    library(stringr)
    context <- c("PHRASE1", "PHRASE2", "PHRASE3")
    str_match(x, paste0("\\*(.*?)\\s+(?:", paste(context, collapse="|"), ")"))[,2]
    # => [1] "NAME ALPHA"   "NAME BETA"    "NAME GAMMA"   "NAME DELTA"   "NAME EPSILON"
    

    请参阅regex demo

    详情

    • \* - 一个 * 字符
    • (.*?) - 第 1 组(在 str_match[,2] 之后访问):除换行符之外的任何零个或多个字符尽可能少
    • \s+(?:PHRASE1|PHRASE2|PHRASE3) - 1 个或多个空格和一个上下文字符串。

    基础 R 解决方案

    x<-c("*NAME ALPHA PHRASE1 BLA BLA TEXT 81249","*NAME BETA PHRASE1 BLA BLA 81229","*NAME GAMMA PHRASE2 BLA BLA TEXT 85129","*NAME DELTA PHRASE3 BLA BLA 86129","*NAME EPSILON PHRASE2 BLA BLA 81729")
    context <- c("PHRASE1", "PHRASE2", "PHRASE3")
    pattern <- paste0("\\*\\K.*?(?=\\s+(?:", paste(context, collapse="|"), "))")
    regmatches(x, regexpr(pattern, x, perl=TRUE))
    ## => [1] "NAME ALPHA"   "NAME BETA"    "NAME GAMMA"   "NAME DELTA"   "NAME EPSILON"
    

    请参阅R demo online。请注意,此方法需要 PCRE 正则表达式才能工作,因此 perl=TRUE 参数是强制性的。

    \K PCRE 构造省略了到目前为止与当前匹配内存缓冲区匹配的文本。 (?=...) 构造是一个正向前瞻,它匹配字符串中的某个位置(这就是为什么它被称为零宽度断言),紧随其后的是前瞻模式。

    【讨论】:

      【解决方案3】:

      替换为strsplit(),然后删除尾随空格

      代码

        sapply(str2, function(z){
          # remove * and whitespaces
          gsub("[*]|\\s+$", "", 
          # split by phrase and choose part of interest
          sapply(strsplit(str1, z)[grepl(z, str1)], "[[", 1))
         })
          
      # $PHRASE1
      # [1] "NAME ALPHA" "NAME BETA" 
      
      # $PHRASE2
      # [1] "NAME GAMMA"   "NAME EPSILON"
      
      # $PHRASE3
      # [1] "NAME DELTA"
      

      数据

      str1 <- c("*NAME ALPHA PHRASE1 BLA BLA TEXT 81249",
      "*NAME BETA PHRASE1 BLA BLA 81229",
      "*NAME GAMMA PHRASE2 BLA BLA TEXT 85129",
      "*NAME DELTA PHRASE3 BLA BLA 86129",
      "*NAME EPSILON PHRASE2 BLA BLA 81729")
      
      str2 <- c("PHRASE1", "PHRASE2", "PHRASE3")
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-11-18
        • 1970-01-01
        • 1970-01-01
        • 2021-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多