java - 将 CIDR 转换为正则表达式的 Java 函数
问题描述
我有一个 Oracle 数据库,其中有一堆 IP 地址作为字符串(varchar2)。我希望能够找到包含在给定 CIDR 块中的那些。由于它不是某种本机“ip”类型,因此我不能使用任何类型的本机 IP 搜索机制。我在想有可能从 cidr 生成一个正则表达式(例如:“10.1.0.0/10”),它会找到正确的值。
任何人都有可以做到这一点的函数或知道java中的库吗?或者任何替代解决方案?
甲骨文 12.1.0.2
解决方案
OP(原始海报)提到了一个函数“inet_aton”,它可以将 IPv4 地址的字符串表示形式转换为其相应的整数值。唉,在 Oracle SQL 和/或 PL/SQL 中没有这样的功能。
在下面的答案中,我展示了可以用 PL/SQL 编写这样的函数的(微不足道的!)方式。然后我演示如何使用它来解决 OP 的问题。
注意OP 提到“正则表达式”作为解决同一问题的可能方法。我怀疑这些方面的任何事情都会像我在下面提出的那样有效。如果块是有类的(也就是说,如果后缀是 8 的倍数),那么确实很容易写一个regexp_like
条件(我们只需要匹配四部分 IP 的第一个、两个或三个“部分”地址)。然而,对于无类块,问题变得更加复杂。尾注
编辑为了它的价值,我只是在一个有 160 万个 IP 地址的表上尝试了转换功能。它在 0.3 秒内将它们全部转换为数字格式。结束编辑
在代码中,我将函数创建为独立对象(函数)。如果愿意,可以在使用它的同一查询中的 WITH 子句中定义该函数。这可能会导致性能稍好一些。(也可以直接在select
查询中使用函数体中的公式,因此在任何地方都没有函数调用,但性能提升可能很小。)
如果性能很重要,OP 可以在存储 IP 地址的表中添加基于函数的索引;然后,对于相对较小的 CIDR 块,只要过滤器具有足够的选择性,查询就应该非常快。
这是将 IPv4 地址从四部分字符串格式转换为整数的函数的一种实现:
create or replace function ip_str_to_num (s varchar2) return number
deterministic
as
pragma udf;
begin
return
((to_number(substr(s,1,instr(s,'.',1,1)-1))*256+
to_number(substr(s,instr(s,'.',1,1)+1,instr(s,'.',1,2)-instr(s,'.',1,1)-1))
)*256+
to_number(substr(s,instr(s,'.',1,2)+1,instr(s,'.',1,3)-instr(s,'.',1,2)-1))
)*256+to_number(substr(s,instr(s,'.',1,3)+1));
end;
/
特别注意pragma udf
- 仅从 Oracle 12.1 开始可用;这使得函数工作得更快,只要它只在 SQL 上下文中使用。
那么这里是一个如何使用这个函数的例子。我创建了一个非常小的“可用地址”表。然后我展示了一个查询,我在其中硬编码了一个 CIDR 块(通常应该将其更改为绑定变量);我展示了我们如何使用转换函数以数字格式生成块中的最小和最大地址,然后我加入地址表以查找属于该块的那些地址。
测试数据:
create table ip_address_list(ip_address varchar2(19));
insert into ip_address_list
select '123.33.2.234' from dual union all
select '230.0.0.1' from dual union all
select '43.233.83.2' from dual union all
select '128.233.2.8' from dual union all
select '72.120.0.1' from dual union all
select '128.232.1.64' from dual
;
commit;
查询和结果:
with
inputs(cidr_block) as (
select '128.224.0.0/10' from dual
)
, prep(min_addr, suffix) as (
select ip_str_to_num(substr(cidr_block, 1, instr(cidr_block, '/') - 1)),
substr(cidr_block, instr(cidr_block, '/') + 1)
from inputs
)
, address_range(min_addr, max_addr) as (
select min_addr, min_addr + power(2, 32 - suffix) - 1
from prep
)
select ip_address
from ip_address_list join address_range
on ip_str_to_num(ip_address) between min_addr and max_addr
order by ip_str_to_num(ip_address)
;
IP_ADDRESS
-------------------
128.232.1.64
128.233.2.8
推荐阅读
- javascript - 如何使用 bootstrap-4-react 在模态中添加条件?
- git - 为什么 AWS EB 工具不使用分支的默认环境?
- android - 如何在获取 API 时修复连接错误?尝试进行身份验证时一直崩溃
- c# - 如果 DbParameter.DbType 是 Binary,那么 DbParameter.Size 的值是多少?
- ruby-on-rails - 为什么 Rails 无法识别请求标头中的 `Accept: application/json`?
- swift - 有没有办法将变量/布尔值携带到视图的超级视图中?
- java - mysql连接-检查与您的mysql服务器版本相对应的手册
- javascript - 如何将 Laravel 环境数据传递给 Vue 组件
- c# - 如何在 c# selenium chromedriver 中选择下拉列表的下拉值而不选择?
- r - 如何将每年从原始单独文件附加到新的合并数据集