【问题标题】:Filtering using multiple regex pattern specifications in R在 R 中使用多个正则表达式模式规范进行过滤
【发布时间】:2018-02-21 21:54:59
【问题描述】:

我有一个过滤问题,我试图根据具有 4 种不同模式中的任何一种的字符串的存在来选择观察结果:

  1. 10 个连续数字的字符串(例如 1250126681)
  2. 13 个连续数字的字符串(例如 9781626724266)
  3. 以“id”开头后跟 9 个连续数字的字符串(例如 id975448501)
  4. 由大写字母和数字组合而成的字符串(长度=10)(例如 B004TLHNOC)

这是一个示例数据集:

FromName<-c("PubA","PubB","PubC","PubB","PubC","PubB")
PostName<-c("https://www.amazon.com/gp/product/1250126681/ref=as_li_tl","https://www.amazon.com/dp/B004TLHNOC/ref=sr_1_1","https://us.macmillan.com/books/9781626724266",
            "https://itunes.apple.com/us/book/six-of-crows/id975448501","http://www.anrdoezrs.net/links/7992675/type/dlg/sid/MAChhjan32018eman/https://www.barnesandnoble.com/w/something-to-howl-about-christine-warren/1127202692","https://www.amazon.com/Beach-House-Cookbook-Mary-Andrews-ebook/dp/B01M2UZS7F/")
df<-cbind(FromName,PostName)

输出应如下所示:

我认为前 2 个模式的正则表达式是:^[0-9]{10}$ 和 ^[0-9]{13}$,我认为 [a-z]{2}\d{9}应该适用于选择第三种模式的观察,但我坚持模式#4。我也不确定如何将多个正则表达式模式组合成一个 dplyr 过滤函数。

【问题讨论】:

  • ^(?:\d{10}(?:\d{3})?|id\d{9}|[A-Z\d]{10})$ 怎么样?您需要在 r 中转义反斜杠。
  • @ctwheels 谢谢。我假设 {3} 应该是 {13},代表 13 位字符串?我不明白您关于在 R 中转义反斜杠的评论。这是您刚刚给我的模式中考虑的因素,还是我需要添加其他逻辑?
  • 在 R 中,正则表达式是一个字符串,但 \ 是一个特殊的转义字符,即使在字符串中也是如此。所以要在你的正则表达式中有\d,你需要在代表正则表达式的字符串中使用\\d
  • @user3614783 正是 C​​alumYou 提到的,但 (?:\d{3})? 是可选的,所以它只是将它附加到 \d{10} 的末尾,而不是单独指定它们为 \d{10}|\d{13}。您可以使用任何一种方法。如果没有 $ 锚点,使用 \d{10}|\d{13} 只会捕获前十位数字(除非您颠倒了选项的顺序)。

标签: r regex dplyr


【解决方案1】:

以下正则表达式应该可以工作:

[0-9]{10}
[0-9]{13}
id[0-9]{9}
[A-Z0-9]{10}

您不应该需要^$,因为您正在尝试匹配字符串中的某些内容。 ^abc$ 将匹配 abc,但不匹配 xabcx

第二个模式将返回第四个模式的子集。任何 10 位数字的字符串也是 10 位数字或大写字母的字符串。所以你只需要三个模式来匹配这四个类别。除非您想以某种方式将 10 个字符的 ONLY 整数字符串与具有整数和字符的字符串区分开来,但情况似乎并非如此。

您可以使用| 来检查多个模式。但是,这将返回第一个匹配项。例如。 str_extract('abcdef','abc|def') 仅返回 abc。如果您知道每个 URL 与任何类别的匹配项不超过 1 个,那就这样做吧。

我喜欢使用来自stringrstr_extract

ProductID = str_extract(PostName, 'id[0-9]{9}|[0-9]{13}|[A-Z0-9]{10}')

【讨论】:

  • 我没有考虑过一种模式是另一种模式的子集,并且我可以使用三种模式来匹配四个类别。还感谢您指出您的方法仅返回第一个匹配项。此数据集不是问题,但请注意。
【解决方案2】:

由于您上面的数据是一个矩阵,我们可以将结果 cbind 如下:

你可以使用basename:

cbind(df[,1],basename(sub("ref.*","",df[,2])))
     [,1]   [,2]           
[1,] "PubA" "1250126681"   
[2,] "PubB" "B004TLHNOC"   
[3,] "PubC" "9781626724266"
[4,] "PubB" "id975448501"  
[5,] "PubC" "1127202692"   
[6,] "PubB" "B01M2UZS7F"  

或者你可以这样做:

cbind(df[,1],sub(".*\\/(\\w+)\\/(?>ref.*)|.*\\/(\\w+)\\S{1,2}$","\\1\\2",df[,2],perl = T))
     [,1]   [,2]          
[1,] "PubA" "1250126681"  
[2,] "PubB" "B004TLHNOC"  
[3,] "PubC" "978162672426"
[4,] "PubB" "id97544850"  
[5,] "PubC" "112720269"   
[6,] "PubB" "B01M2UZS7F"  

【讨论】:

    猜你喜欢
    • 2018-06-23
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 2015-03-21
    • 2012-06-08
    • 2013-05-29
    • 2018-04-13
    • 1970-01-01
    相关资源
    最近更新 更多