如何在 Scala 中将 IPv4 地址与 Long 进行转换

Posted

技术标签:

【中文标题】如何在 Scala 中将 IPv4 地址与 Long 进行转换【英文标题】:How to Convert IPv4 Addresses to/from Long in Scala 【发布时间】:2016-04-20 07:24:19 【问题描述】:

我正在寻找一个具有 2 个函数的基本实用程序,用于在 Scala 中将 IPv4 地址与 Long 进行转换,例如将“10.10.10.10”转换为其 Long 表示的 168430090 并返回。诸如此类的基本实用程序存在于许多语言(例如 python)中,但似乎需要为 JVM 的每个人重新编写相同的代码。

统一 IPv4ToLong 和 LongToIPv4 函数的推荐方法是什么?

【问题讨论】:

【参考方案1】:

结合leifbatterman 和Elesin Olalekan Fuad 的想法,避免乘法和幂运算:

def ipv4ToLong(ip: String): Option[Long] = Try(
  ip.split('.').ensuring(_.length == 4)
    .map(_.toLong).ensuring(_.forall(x => x >= 0 && x < 256))
    .reverse.zip(List(0,8,16,24)).map(xi => xi._1 << xi._2).sum
).toOption

将Long转换为点分格式的字符串:

def longToipv4(ip: Long): Option[String] = if ( ip >= 0 && ip <= 4294967295L) 
  Some(List(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000).zip(List(0,8,16,24))
    .map(mi => ((mi._1 & ip) >> mi._2)).reverse
    .map(_.toString).mkString("."))
 else None

【讨论】:

List(1,1,1).scanRight((""+(0xff &amp; ip),ip&gt;&gt;8))case (_,(_,n))=&gt; (""+(0xff &amp; n), n&gt;&gt;8).map(_._1).mkString(".") 同样,在ipv4ToLong() 中将reversezipmapsum 替换为foldLeft(0)((s,l) =&gt; (s&lt;&lt;8)+l) @jwvh,非常好。我不得不使用foldLeft(0L)...。【参考方案2】:
import java.net.InetAddress
def IPv4ToLong(dottedIP: String): Long = 
  val addrArray: Array[String] = dottedIP.split("\\.")
  var num: Long = 0
  var i: Int = 0
  while (i < addrArray.length) 
    val power: Int = 3 - i
    num = num + ((addrArray(i).toInt % 256) * Math.pow(256, power)).toLong
    i += 1
  
  num


def LongToIPv4 (ip : Long) : String = 
  val bytes: Array[Byte] = new Array[Byte](4)
  bytes(0) = ((ip & 0xff000000) >> 24).toByte
  bytes(1) = ((ip & 0x00ff0000) >> 16).toByte
  bytes(2) = ((ip & 0x0000ff00) >> 8).toByte
  bytes(3) = (ip & 0x000000ff).toByte
  InetAddress.getByAddress(bytes).getHostAddress()


scala> IPv4ToLong("10.10.10.10")
res0: Long = 168430090

scala> LongToIPv4(168430090L)
res1: String = 10.10.10.10

【讨论】:

【参考方案3】:

试试ipaddr scala library。创建一个 IpAddress 并获取它的长值,如下所示:

val ip1: IpAddress = IpAddress("192.168.0.1")
val ip1Long = ip1.numerical // returns 3232235521L

【讨论】:

【参考方案4】:

这对于ipv4 来说非常简单:

def ipToLong(ip:String) = ip.split("\\\\.").foldLeft(0L)((c,n)=>c*256+n.toLong)

def longToIP(ip:Long) = (for(a<-3 to 0 by -1) yield ((ip>>(a*8))&0xff).toString).mkString(".")

【讨论】:

避免乘法:def longToIP(ip:Long) = (for(bits&lt;-24 to 0 by -8) yield ((ip&gt;&gt;bits)&amp;0xff).toString).mkString(".")`【参考方案5】:

我有一个 GitHub gist 可以解决这个问题。 gist 包含从 IP 转换为 Long 的代码,反之亦然。访问https://gist.github.com/OElesin/f0f2c69530a315177b9e0227a140f9c1

代码如下:

def ipToLong(ipAddress: String): Long = 
   ipAddress.split("\\.").reverse.zipWithIndex.map(a=>a._1.toInt*math.pow(256,a._2).toLong).sum


def longToIP(long: Long): String = 
   (0 until 4).map(a=>long / math.pow(256, a).floor.toInt % 256).reverse.mkString(".")

享受

【讨论】:

【参考方案6】:

添加到Elesin Olalekan Fuad's 答案可以使其更加健壮,如下所示:

def ipToLong(ip: String): Option[Long] = 
  Try(ip.split('.').ensuring(_.length == 4)
    .map(_.toLong).ensuring(_.forall(x => x >= 0 && x < 256))
    .zip(Array(256L * 256L * 256L, 256L * 256L, 256L, 1L))
    .map  case (x, y) => x * y 
    .sum).toOption


def longToIp(ip: Long): Option[String] = 
  if (ip >= 0 && ip <= 4294967295L)
    Some((0 until 4)
      .map(a => ip / math.pow(256, a).floor.toInt % 256)
      .reverse.mkString("."))
  else
    None

【讨论】:

【参考方案7】:

我喜欢@jwvh 对 ipv4ToLong 的评论。至于longToIpv4,简单点:

def longToIpv4(v:Long):String = (for (i > (i * 8)) & 0x000000FF).reverse.mkString(".")

【讨论】:

以上是关于如何在 Scala 中将 IPv4 地址与 Long 进行转换的主要内容,如果未能解决你的问题,请参考以下文章

在python中将IPv4地址转换为十六进制

python - 如何使用pyproj在python中将lat/lon转换为UTM?

前端周报:Scala.js发布;IPv4地址耗尽;JavaScript状态调查已开放

ipv4与ipv6如何转换?计算方法是啥?

如何在Scala中将文件作为字节数组读取

在 IntelliJ IDE 中将 Spark 与 Scala 项目集成时出错