В R - подстрока на основе повторяющегося символа - PullRequest
0 голосов
/ 03 июля 2018

У меня есть две таблицы. В одной таблице (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", найденное в любом месте в "10.100.20.13"). Я использую это поле для объединения / слияния. При использовании R я понимаю, что цикл foreach - не самый эффективный способ, которым я должен это делать, а в другом приложении это занимает много времени, что является одной из причин, по которым я перехожу к R.

Я не видел способа сделать то же самое с данным типом данных (я выполнял слияния и объединения, но я не вижу способа сделать это без достаточного доступа к двум переменным, чтобы использовать их для связывания два стола).

В прошлом я мог использовать такие методы R, как sqldf, charindex и leftstr, для поиска конкретного символа "." и вытащить все перед этим, но трудность заключается в том, что для того, чтобы сделать это таким образом, мне нужно искать 3-е вхождение периода "." вместо первого. Я не видел способ сделать это, но если есть способ, это может быть лучше .

Моей следующей попыткой было использование strsplit и sapply на IP-адресе с идеей повторной сборки только первых трех частей для создания подсети для сопоставления (в новом столбце / переменной). Это выглядело так:

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

Это дает "Большой список", который делает данные похожими на это:

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

Но, пытаясь собрать его вместе, я также теряю промежуток между октетами. Пример кода:

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

Это производит что-то вроде этого:

"1010020"

В конце у меня два вопроса:

1) Существует ли метод для простого сравнения, которое я делал ранее (по сути, выполняется слияние переменной подсети в Таблице 1 с «большей частью» IP-адреса в Таблице 2, исходя из всего, что было до третьего периода (». ") без необходимости его разделения и повторной сборки поля IPAddress?

2) Если нет, то нахожусь ли я на правильном пути, пытаясь разделить, а затем собрать заново? Если да, что я делаю не так с повторной сборкой или есть более простой / лучший способ сделать это?

Спасибо и дайте мне знать, что еще вам нужно.

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Я думаю, что вы по существу спрашиваете, как соединить эти два стола, верно? Если это так, я бы сделал это так:

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, заменяя / удаляя точку (\\.), за которой следуют от одного до трех чисел (\\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
0 голосов
/ 03 июля 2018
unlist(strsplit(SubnetTable$Subnet,split=",")) %in% 
gsub("^(\\d{2,3}.\\d{2,3}.\\d{2,3}).*$","\\1",IPTable$IPAddress)

Это даст вам вектор класса 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  
...