【问题标题】:R: Regex - Capture numbers in string and replacing them in another column (Capturing Groups)R:正则表达式 - 捕获字符串中的数字并在另一列中替换它们(捕获组)
【发布时间】:2015-04-27 19:21:34
【问题描述】:

我有这个基本数据框:

我想在一列中搜索一个 SKU(8 位),将其放入一个变量(捕获组)中,然后将其放入一个新列中:“SKU_solo”。

我不需要“\1”,但需要前 8 位数字。如何在我的代码中创建捕获组?

这是我的代码:

我正在使用“dplyr”

urls_na <- urls_na %>%
           mutate(SKU_solo = NA, #initialize the new column
                  SKU_solo = ifelse(grepl("([0-9]+)", Page), "\\1",SKU_solo))




                     Page                   Categoria   Page.Views       SKU_solo
1   5   /Cajon_Criolla_20141024                 #N/A             7           \1 
2   6   /Linon_20141115_20141130                #N/A           564           \1
3   7   /Cat/LIQUID                             #N/A             1           NA
4   8   /c_puertas_20141106_20141107            #N/A            34           \1 
5   9   /C_Puertas_3_20141017_20141018          #N/A             2           \1
6   10  /c_puertas_navidad_20141204_20141205    #N/A        187319           \1

期望的输出:

                     Page                   Categoria   Page.Views       SKU_solo
1   5   /Cajon_Criolla_20141024                 #N/A             7       20141024
2   6   /Linon_20141115_20141130                #N/A           564       20141115
3   7   /Cat/LIQUID                             #N/A             1           NA
4   8   /c_puertas_20141106_20141107            #N/A            34       20141106
5   9   /C_Puertas_3_20141017_20141018          #N/A             2       20141017
6   10  /c_puertas_navidad_20141204_20141205    #N/A        187319       20141204 

注意事项:

1) ifelse 和 grepl 有助于进行捕获和替换。但是,它只是返回: \1 作为字符串。

2) 可能还有其他数字,如第 5 行。但重要的是第一个 SKU(8 位组)。

更新

如您所见,我可以在 SKU_solo 列中打印“\1”。我知道还有其他方法可以做到这一点,但我的代码有什么问题?

我想使用 Regex 中的“捕获组”特性。我已经读过,当某物在“()”内时,它从左到右将值 1 分配给 ...。在我的代码中:ifelse(grepl("([0-9]+)", Page), "\\1",SKU_solo)) ... ([0-9]+) 应该是分配编号 1 ...这就是为什么在我使用:"\1" 来引用它之后。我不明白,为什么它不起作用,只在“SKU_solo”列中输入:“\1”。

【问题讨论】:

    标签: regex r


    【解决方案1】:

    您可以为此使用stringr 包:

    library(stringr)
    urls_na <- urls_na %>%
               mutate(SKU_solo = NA, #initialize the new column
                      SKU_solo = str_match(Page, "([0-9]{8})")[,1])
    

    请注意,我也更改了您的正则表达式,因为您正在寻找一个 8 位数字。

    请注意:

    str_match(Page, "([0-9]{8})")[,1]

    将返回完整的比赛。如果您想返回单个组,您可以使用索引 2 向前。

    来自stringr 文档:

    Value:
    
         character matrix. First column is the complete match, followed by
         one for each capture group
    

    【讨论】:

    • 感谢您。我正在调查 stringr 包。但是,我需要对它们进行分组,因为如您所见,我在某些行中有 2 组 8 位数字。在我想使用第二组 8 位数字之后......所以在我的代码中,我只需要引用第二组。
    • str_match 给你。来自文档:First column is the complete match, followed by one for each capture group。所以你应该能够索引以获得你想要的任何组。
    • 从您的代码中,我看到:1)查看页面列,2)查看一组 8 位数字。但是,我没有看到分组部分,这对我将来是必要的。这个非常重要。 **请在您的答案中添加一些 cmets,也许我错了。
    【解决方案2】:

    您的代码中有几个问题。首先,您不设置数字的数量。其次,您不要告诉它“贪婪”以匹配第一项,用 (.*?) 完成。

    你需要使用正则表达式

         "(.*?)_([0-9]{8})"
    

    解决您的问题 2)

    但是你的“捕获组”不起作用,因为它是为了在 sub 或 gsub 等函数中工作。你不能在两者之间传递它 测试 和 是的 的论点 如果别的() 如果要保留构造,则需要重复 gsub 两次。

        matchingExp <- "(.*?)_([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])(.*)$"
        urls_na <- urls_na %>% 
                     mutate(SKU_solo=NA,
                     SKU_solo=ifelse(grepl(matchingExp,Page),sub(matchingExp,"\\2",Page),Page))
    

    但是当您调用 regexp 两次时,效率非常低。为避免这种情况,您可以使用结果必须是数字的事实,并且如果它与您的文件名不匹配,则不能仅是数字(如果您有疑问,您可以随时添加首字母“a”):

        urls_na <- urls_na %>% mutate(SKU_solo=as.numeric(sub("(.*?)_([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])(.*)$","\\2",Page)))
    

    以上所有方法在这里都可以正常工作。

    @dave 请注意,我实际上有 n 倍 [0-9] 和 [0-9]{n} 之间的差异。我发布了一个问题here

    【讨论】:

    • 谢谢。我希望指出我的错误(代码中的错误)。
    • @cmbarbu,您的代码在 SKU_solo" 列中打印“\2”。
    【解决方案3】:

    dplyr:

    urls_na <- urls_na %>%
               mutate( SKU_solo = ifelse(grepl('_([0-9]{8})$',Page), 
                                        gsub('^.*_(\\d{8})$','\\1',Page),
                                        NA))
    

    基础R:

    urls_na$SKU_solo <- ifelse(grepl('_([0-9]{8})$',urls_na$Page), 
                               gsub('^.*_(\\d{8})$','\\1',urls_na$Page)
                               NA)
    

    【讨论】:

    • ifelse( , '\\1', ) 的第二个参数只是一个文字字符串,而当第一个参数计算为 TRUE 时,第二个参数应该计算为你想要的任何值。在我的解决方案中,第二个参数是对 substr(Page,...) 的调用,其计算结果为所需的 SKU。
    • 还要注意你不需要初始化你的列; ifelse() 已被矢量化,因此您只需调用 mutate(SKU_solo = ifelse(grepl("([0-9]+)", Page), SomethingThatEvalutesToTheSKU,NA))
    • 我明白你说的。这就是为什么我想使用正则表达式中的“捕获组”特性。我已经读过,当某物在“()”内时,它从左到右将值 1 分配给 ...。在我的代码中:ifelse(grepl("([0-9]+)", Page), "\\1",SKU_solo)) ...([0-9]+) 应该是分配数字 1...这就是为什么在我使用:“\\1”来引用它之后。我不明白,为什么它不起作用。
    • 关于"\\1" 指的是第一个捕获的组,您是正确的,但它仅用于替换模式,即sub()gsub() 的第二个参数。
    • 所以,我的代码不起作用,因为我需要使用“sub()”而不是 grepl?谢谢。
    猜你喜欢
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2020-08-24
    • 2015-06-30
    • 2019-12-27
    • 1970-01-01
    • 2016-12-15
    • 2012-04-11
    相关资源
    最近更新 更多