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

In R - Substring based on repeating character

我有两个 table。在一个 table(IPTable) 中,table 中有一列包含 IP 地址(看起来像这样:“10.100.20.13”)。我正在尝试将其中的每一个与另一个 table (SubnetTable) 中包含子网地址的列中的数据相匹配(看起来像这样:“10.100.20”,本质上是 IP 地址的缩短版本 -第三节之前的所有内容)。这两个变量似乎都是 chr 向量。

原始 IP 数据基本上是这样的:

IPTable$IPAddress

10.100.20.13

10.100.20.256

10.100.200.23

101.10.13.43

101.100.200.1

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

子网表$子网

Varies

10.100.20

Remote Subnet

10.100.200, 101.10.13

Unknown Subnet

备注:

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

我没有看到一种方法可以对这种类型的数据做同样的事情(我已经完成了合并和连接,但是我没有看到一种方法可以做到这一点,除非两个变量足够相似以用于link 两个 table)。

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

我的下一次尝试是在 IP 地址上使用 strsplit 和 sapply,只重新组合前三个部分以创建要匹配的子网(在新的 column/variable 中)。看起来像这样:

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

这给出了一个 "Large List" 使得数据看起来像这样:

chr [1:4] "10" "100" "20 "13"

但是当我试图把它放回原处时,我也失去了八位字节之间的句点。示例代码:

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

这会产生这样的结果:

"1010020"

最后我有两个问题:

1) 是否有一种方法可以进行我之前所做的简单比较(本质上是将 Table1 的子网变量合并到 Table2 的 IP 地址的 "most",基于第三个之前的所有内容句点 (".") 而不必将其拆分并重新组装 IPAddress 字段?

2) 如果不是,我尝试拆分然后重新组合是否在正确的轨道上?如果是这样,我在重新组装时做错了什么,或者有 easier/better 的方法吗?

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

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

这将为您提供一个 class logical 的向量,该向量将 TRUE/FALSE 与子网中的每个项目相匹配(为其中包含逗号的项目提供多个响应)。或者,您可以翻转两侧以获得每个 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  

我认为您实质上要问的是如何连接这两个表,对吗?如果是这样的话,我会这样做:

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 向量仅包含一个 ", " 来分隔两个子网。 IE。没有像这样的字符串 "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

接下来我们通过 replacing/deleting 一个点 (\.) 后跟一到三个数字 (\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

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

IPTable_subnet <- 
  dplyr::left_join(
    x = IPTable, 
    y = SubnetTable_tidy,
    by = "Subnet"
  )

IPTable_subnet
#>       IPAddress      Subnet subnet_id
#> 1  10.100.20.13   10.100.20         2
#> 2 10.100.20.256   10.100.20         2
#> 3 10.100.200.23  10.100.200         4
#> 4  101.10.13.43   101.10.13         4
#> 5 101.100.200.1 101.100.200        NA