在 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
备注:
有时子网条目在一个字段中包含两个子网,以逗号分隔
IP 地址字段在组之间的位置不一致(例如 - 可能存在“10.110.20.13”以及“101.10.20.13")
在一个不同的脚本应用程序中,我能够简单地将它们作为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
我有两个 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
备注:
有时子网条目在一个字段中包含两个子网,以逗号分隔
IP 地址字段在组之间的位置不一致(例如 - 可能存在“10.110.20.13”以及“101.10.20.13")
在一个不同的脚本应用程序中,我能够简单地将它们作为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