scala - 在 Scala 中验证 IP 地址
问题描述
我想验证 scala 中的 IP 地址。我已经实现了该方法,但我看到了一些错误。
任何人都可以调查它并建议他们是否有更好的解决方案。我不想在功能上实现。
def validIPAddress(IP: String): String = {
var isValidIP = true
if(IP.contains(":")) {
var numbers= IP.split(":") //create an array
if (numbers.length!=8) return "Neither"
for (n <- numbers) {
if(n.length = 0 or n.length > 4) return "Neither"
else {
for (m <- n) {
if(!m in "0123456789abcdefABCDEF") return "Neither"
}
}
}
return "IPv6"
}
else if(IP.contains(".") { //192.168.1.1
nums = IP.split(".")
if(nums.length!=4) isValidIP = false //Array.length
else {
for (a <- nums) {
println(a)
try {
var intA = a.toInt
if(intA <=0 || IntA > 255) {
isValid = false
}
} catch (NumberFormatException e) {
case e: Exception => None
}
}
if(isValid == true) {
println("Valid IP")
} else {
println("Invalid IP")
}
}
} return "IPv4"
else {
return "neither"
}
}
解决方案
您可能不打算实现功能,但在您的示例中根本不需要命令式代码,并且return
s 和var
s 在阅读代码的意图时会引起一些严重的问题。
我会将代码重写为这样的
sealed trait IP extends Product with Serializable
object IP {
final case class V4(a: Int, b: Int, c: Int, d: Int) extends IP
final case class V6(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, h: Int) extends IP
}
val ipV4 = """(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})""".r
val ipV6 = """([0-9a-fA-F]+):""".r
def validIPAddress(ip: String): Either[String, IP] = {
def parseV4(s: String) = {
val i = Integer.parseInt(s)
if (0 <= i && i <= 255) Right(i) else Left(s"$i is not a valid IPv4 number")
}
def parseV6(s: String) = Integer.parseInt(s, 16)
ip match {
case ipV4(a, b, c, d) =>
for {
a1 <- parseV4(a)
b1 <- parseV4(b)
c1 <- parseV4(c)
d1 <- parseV4(d)
} yield IP.V4(a1, b1, c1, d1)
case ipV6(a, b, c, d, e, f, g, h) =>
// technically speaking this isn't exhausting all possible IPv6 addresses...
// as this regexp would ignore e.g. ::1 or ::
Right(IP.V6(parseV6(a), parseV6(b), parseV6(c), parseV6(d), parseV6(e), parseV6(f), parseV6(g), parseV6(h)))
case _ =>
Left(s"$ip is neither V4 nor V6 format")
}
}
以便更容易地跟踪和调试错误,尽管当我检查此实现并不真正符合 IPv6 所做的事情时,因为需要对正则表达式的使用进行一些调整。事实上,如果我没有时间写下 15-20 个测试用例,我宁愿完全避免推出自己的解决方案。
因此,除非有理由实现您自己的验证器,否则我会将该任务委托给一些已经测试过处理极端情况的库。
但是,如果您必须执行以下操作:
- 不要使用
return
- 在 Scala 中,它的作用与您认为的不同 - 除非您正在优化,否则不要使用
var
s - 您使用它们的方式与优化无关(isValid
从未使用过,所以为什么要覆盖它?并且其他变量永远不会被修改) - 不要对所有事情都使用字符串,因为这本身就是自找麻烦(例如
"neither"
,"Neither"
调用者应该.equalsIgnoreCase
在你的代码上使用来检查结果吗?) - 从基于规范编写的测试开始。当我翻译您的代码时,它无法使用有效的 IPv6 地址。如果我跳过 Iv6 是固定大小的要求,它会更短:
sealed trait IP extends Product with Serializable
object IP {
final case class V4(a: Int, b: Int, c: Int, d: Int) extends IP
final case class V6(values: List[Int]) extends IP
}
val ipV4 = """(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})""".r
val ipV6 = """([0-9a-fA-F]*)((:[0-9a-fA-F]*){2,})""".r
def validIPAddress(ip: String): Either[String, IP] = {
def parseV4(s: String) = {
val i = Integer.parseInt(s)
if (0 <= i && i <= 255) Right(i) else Left(s"$i is not a valid IPv4 number")
}
def parseV6(s: String) = if (s.isEmpty) 0 else Integer.parseInt(s, 16)
ip match {
case ipV4(a, b, c, d) =>
for {
a1 <- parseV4(a)
b1 <- parseV4(b)
c1 <- parseV4(c)
d1 <- parseV4(d)
} yield IP.V4(a1, b1, c1, d1)
case ipV6(head, tail, _) =>
val segments = head +: tail.substring(1).split(':')
Right(IP.V6(segments.map(parseV6).toList))
case _ =>
Left(s"$ip is neither V4 nor V6 format")
}
}
它处理了更多正确的案例,但还远未准备好。因此,如果可以的话 - 避免自己动手并使用图书馆。
推荐阅读
- c# - 列表中的笛卡尔积
- node.js - Heroku/Nodejs 启动失败,at=error code=H10 desc="App
- php - 无法使用 PHP 在数据库中增加 ID
- reactjs - 为什么我的 this.props.data 在渲染函数之前的任何地方都未定义?
- javascript - 如何避免将 localhost 添加到 .js src
- c++ - C++11无锁序列号生成器安全吗?
- visual-studio-code - Ubuntu 下的 Visual Studio Code 上是否有工具选项?
- c++ - 为什么将指针分配给双变量时出现错误
- arrays - 在 Mongo 中,映射数组并更新文档
- linux - abyss-pe:使用一个命令组装多个基因组的变量