在R中-基于重复字符的子字符串

时间:2018-07-03 12:22:35

标签: r string split ip-address

我有两个桌子。在一个表(IPTable)中,一个表中有一列包含IP地址(如下所示:“ 10.100.20.13”)。我正在尝试将每个数据与另一个表(SubnetTable)中包含子网地址的列中的数据进行匹配(看起来像这样:“ 10.100.20”,本质上是IP地址的简化版本-第3个之前的所有内容期)。这两个变量似乎都是chr向量。

基本上,原始IP数据如下所示:

IPTable $ IPAddress

  

10.100.20.13

     

10.100.20.256

     

10.100.200.23

     

101.10.13.43

     

101.100.200.1

和我正在比较的原始子网数据如下:

SubnetTable $ Subnet

  

变化

     

10.100.20

     

远程子网

     

10.100.200,101.10.13

     

未知子网

注意:

  • 有时子网条目在用逗号分隔的字段中包含两个子网

  • IPAddress字段在组之间的位置不一致(例如-可能存在“ 10.110 .20.13”和“ 101.10 ”。 20.13“)

不同脚本应用程序中,我能够在foreach循环中简单地将它们作为字符串进行比较。按照这种逻辑,它将遍历子网数据(SubnetTable)中的每个条目,将其与逗号分隔(以说明具有多个子网地址的条目),然后检查是否在“ IP地址”字段中找到匹配项(例如-是在“ 10.100.20.13”中的任意位置找到的“ 10.100.20”)。我使用该字段进行联接/合并。在使用R时,我了解到foreach循环并不是我应该这样做的最有效方法,而在其他应用程序中则需要很长时间,这就是我转向R的部分原因。

我没有看到针对这种类型的数据执行相同操作的方法(我已经完成了合并和联接,但是我没有看到一种方法,而没有获得两个足够相似的变量来链接两张桌子)。

过去,我已经能够使用sqldf,charindex和leftstr之类的R方法来查找特定字符“”。并把所有东西都拉到前面,但是这里的困难是要那样做,我需要寻找“”期间的第三次出现。而不是第一个。 我没有看到这样的方法,但是如果有一种方法,那可能是最好的

我的下一个尝试是在IP地址上使用strsplit和sapply,其想法是仅重新组装前三个部分以创建要匹配的子网(在新列/变量中)。看起来像这样:

IPClassC <- sapply(strsplit(Encrypt_Remaining5$IPAddress, "[.]"), `[`)

这给出了一个“大列表”,使数据看起来像这样:

  

chr [1:4]“ 10”“ 100”“ 20” 13“

但是,当尝试将其放回原位时,我也会丢失八位位组之间的时间间隔。示例代码:

paste(c(IPClassC[[1]][1:3]), sep ="[.]", collapse = "")

这将产生如下内容:

  

“ 1010020”

最后我有两个问题:

1)是否有一种方法可以做我之前做的简单比较(本质上是将表1的子网变量合并到表2的IP地址的“大部分”,这种合并基于第三段之前的所有内容)。 ”),而不必将其拆分并重新组合IPAddress字段?

2)如果不是,我是否在尝试拆分然后重新组装的正确轨道上?如果是这样,我在进行重组时出了什么问题?或者有更简便/更好的方法吗?

谢谢,让我知道您还需要什么。

2 个答案:

答案 0 :(得分:1)

我认为您实际上要问的是如何将这两个表结合在一起,对吗?如果是这样,我会这样:

library(tidyr)
suppressPackageStartupMessages(library(dplyr))

IPTable <-
  data.frame(
    IPAddress =
      c(
        "10.100.20.13",
        "10.100.20.256",
        "10.100.200.23",
        "101.10.13.43",
        "101.100.200.1"
      ), 
    stringsAsFactors = FALSE
  )

我不确定您的SubnetTable是否真的像这样,即将子网地址与其他文本混合在一起吗?无论如何,此解决方案实际上会忽略其他文本。

SubnetTable <-
  data.frame(
    subnet_id = 1:5,
    Subnet =
      c(
        "Varies",
        "10.100.20",
        "Remote Subnet",
        "10.100.200, 101.10.13",
        "Unknown Subnet"
      ), 
    stringsAsFactors = FALSE
  )

首先,我们将多个子网分成多行。请注意,这假设SubnetTable$Subnet向量仅包含一个", "来分隔两个子网。即没有像这样的"Unknown, Subnet"字符串,否则它们也将分为两行。

SubnetTable_tidy <- tidyr::separate_rows(SubnetTable, Subnet, sep = ", ")
SubnetTable_tidy
#>   subnet_id         Subnet
#> 1         1         Varies
#> 2         2      10.100.20
#> 3         3  Remote Subnet
#> 4         4     10.100.200
#> 5         4      101.10.13
#> 6         5 Unknown Subnet

接下来,我们通过替换/删除点(Subnet),然后是一到三个数字(\\.),然后是字符串的结尾({{1}),来提取\\d{1,3} })来自$

IPTable$IPAddress

现在我们可以连接两个表了。

IPTable$Subnet <- gsub("\\.\\d{1,3}$", "", IPTable$IPAddress)
IPTable
#>       IPAddress      Subnet
#> 1  10.100.20.13   10.100.20
#> 2 10.100.20.256   10.100.20
#> 3 10.100.200.23  10.100.200
#> 4  101.10.13.43   101.10.13
#> 5 101.100.200.1 101.100.200

答案 1 :(得分:0)

unlist(strsplit(SubnetTable$Subnet,split=",")) %in% 
gsub("^(\\d{2,3}.\\d{2,3}.\\d{2,3}).*$","\\1",IPTable$IPAddress)

这将为您提供一个logical类的向量,该向量与子网中的每个项目都匹配TRUE / FALSE(对其中包含逗号的项目给出多个响应)。或者,您可以翻转两侧以获取每个IPAddress的逻辑列表,并告诉您该IP地址是否存在于子网列表中。

这是您要找的吗?

您也可以使用charmatch获得类似的结果:

sapply(strsplit(SubnetTable$Subnet, split=","), charmatch, IPTable$IPAddress)

这将为您的示例数据提供以下结果:

[[1]]
[1] NA

[[2]]
[1] 0

[[3]]
[1] NA

[[4]]
[1]  3 NA

[[5]]
[1] NA

请注意,只有一个匹配项时,您会得到它的索引,但是如果有多个匹配项,则值为0

最后,翻转此按钮将为您提供IP地址与以下地址匹配的子网中的索引列表:

sapply(gsub("^(\\d{2,3}.\\d{2,3}.\\d{2,3}).*$","\\1",IPTable$IPAddress), charmatch, SubnetTable$Subnet)

导致:

10.100.20   10.100.20  10.100.200   101.10.13 101.100.200 
      2           2           4          NA          NA