【问题标题】:Scala structured data extraction via regex and pattern matching通过正则表达式和模式匹配提取 Scala 结构化数据
【发布时间】:2017-06-07 20:51:37
【问题描述】:

给定字符串格式的结构化数据,如何使用模式匹配和正则表达式有效地提取部分数据?

例子:

val input = Seq("name-12345","inval1d-12345","invalid-12here123","hello-54321","inval1d-1aa2")

case class Client(name:Option[String],clientID:Option[Int])

def parseClient(input:String):Option[Client] = {
  val clientRegex = """([a-zA-Z]+)-([0-9]+)""".r
  Option(input).flatMap(in => {
    in match {
      case clientRegex(name,clientID) => Some(Client(Some(name),Some(clientID.toInt)))
      case _ => None
    }
  })
}

input.map(parseClient)

然而,这个问题是,如果我无法验证结构化数据的单个部分,那么我不会解析它。

我如何使用正则表达式在分层庄园中进行定义,例如:

val nameRegex = """([a-zA-Z]+)""".r
val clientIDRegex = """([0-9]+)""".r

然后将这些组合在一个模式中匹配?

示例的输出:

Seq(
 Some(Client(Some("name"),Some(12345)))
 ,None
 ,None
 ,Some(Client(Some("hello"),Some(54321)))
 ,None
)

所需的输出:

Seq(
 Some(Client(Some("name"),Some(12345)))
 ,Some(Client(None,Some(12345)))
 ,Some(Client(Some("invalid"),None))
 ,Some(Client(Some("hello"),Some(54321)))
 ,None
)

【问题讨论】:

  • 您提供的输入的预期输出是什么?
  • @WiktorStribiżew 我已经编辑了这个问题,抱歉

标签: regex scala pattern-matching


【解决方案1】:

这应该给出预期的结果:

val input = Seq("name-12345", "inval1d-12345", "invalid-12here123", "hello-54321")

case class Client(name: Option[String], clientID: Option[Int])

def parseClient(input: String): Option[Client] = {
  val clientRegex = """(?:([a-zA-Z^-]+)|[^-]*)-(?:([0-9]+)|.*)""".r
  input match {
    case clientRegex(null, null) => None
    case clientRegex(name, id) => Some(Client(Option(name), Option(id).map(_.toInt)))
    case _ =>
      None
  }
}

input.map(parseClient)

我删除了 flatMap 构造,因为这是不必要的。 这里有趣的部分是正则表达式:

"""(?:([a-zA-Z^-]+)|[^-]*)-(?:([0-9]+)|.*)"""

我对其进行了更改,因此它需要正确的值,因此将其捕获到组中(([a-zA-Z^-]+) 用于名称,([0-9]+) 用于 id)但还添加了其他情况(没有有效的名称或 id)。一切都在非捕获组 (?:) 中,因此分组正确。

如果捕获组中的某些内容与预期不符,则该组将为空,这在匹配案例中进行处理。

编辑 对代码进行了更正,使其适用于完全无效的输入,并删除了不必要的 if 语句

编辑 2 根据 OP 的注释调整代码,利用 Option(null) => None 评估

【讨论】:

  • 谢谢,我最终使用了这个,但我将案例改为: case clientRegex(null,null) => None case clientRegex(name,clientID) => Some(Client(Option(name), Option(clientID).map(_.toInt))) case _ => None
  • 不错,甚至不知道,Option(null) 的计算结果为 None。将调整代码
【解决方案2】:

您可能正在寻找可以链接的应用程序之类的东西。 你可以使用来自猫的Validated 类型来做这样的事情:

val houseNumber = parseClient("house_number").andThen{ n =>
   if (isValid(n)) Validated.valid(n)
   else Validated.invalid(ParseError("house_number"))
}

和 我会选择使用atto: 它具有ParseResult 类型,保留解析字符串的所有信息。

【讨论】:

  • 对不起,我没有正确解释自己,请看预期的输出
  • @AdamPitt 将ParseResult 映射到您的预期输出很简单,好处是您不必自己实现。
猜你喜欢
  • 2018-10-25
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 2013-02-02
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多