【问题标题】:Scala: split string via pattern matchingScala:通过模式匹配拆分字符串
【发布时间】:2014-02-05 21:59:44
【问题描述】:

是否可以像

那样将字符串拆分成词法
"user@domain.com" match {
    case name :: "@" :: domain :: "." :: zone => doSmth(name, domain, zone)
}

换句话说,与列表的方式相同......

【问题讨论】:

  • 我不确定你是否能做到,但我可以解释为什么你的例子不起作用。本质上,您拥有的是字符串列表的匹配器,因为:: case class,又名“cons”运算符,构建了一个元素列表。您需要的是一个 case 类,它接受两个列表并将它们连接起来,就像 ::: 运算符(但不幸的是没有 ::: 与 cons 一样的 case 类)。

标签: string scala split functional-programming pattern-matching


【解决方案1】:

是的,您可以使用 Scala 的 Regex 功能做到这一点。

我找到了一个email regex on this site,如果这不适合你,请随意使用另一个:

[-0-9a-zA-Z.+_]+@[-0-9a-zA-Z.+_]+\.[a-zA-Z]{2,4}

我们要做的第一件事是在组周围添加括号:

([-0-9a-zA-Z.+_]+)@([-0-9a-zA-Z.+_]+)\.([a-zA-Z]{2,4})

这样,我们有三组:@ 之前的部分,@. 之间的部分,最后是 TLD。

现在我们可以从中创建一个 Scala 正则表达式,然后使用 Scala 的 pattern matching unapply 将正则表达式中的组绑定到变量:

val Email = """([-0-9a-zA-Z.+_]+)@([-0-9a-zA-Z.+_]+)\.([a-zA-Z]{2,4})""".r
Email: scala.util.matching.Regex = ([-0-9a-zA-Z.+_]+)@([-0-9a-zA-Z.+_]+)\.([a-zA-Z]    {2,4})


"user@domain.com" match {
    case Email(name, domain, zone) =>
       println(name)
       println(domain)
       println(zone)
}

// user
// domain
// com

【讨论】:

  • +1 这很容易成为我见过的语言处理正则表达式的最佳方式之一。比许多语言中的替代方案要好得多,迫使您手动访问groups 对象并通过索引或名称找到正确的匹配项。很好的答案。
【解决方案2】:

Scala 2.13 开始,可以通过unapplying a string interpolator 模式匹配Strings:

val s"$user@$domain.$zone" = "user@domain.com"
// user: String = "user"
// domain: String = "domain"
// zone: String = "com"

如果您期望输入格式错误,您也可以使用匹配语句:

"user@domain.com" match {
  case s"$user@$domain.$zone" => Some(user, domain, zone)
  case _                      => None
}
// Option[(String, String, String)] = Some(("user", "domain", "com"))

【讨论】:

    【解决方案3】:

    一般来说,正则表达式效率极低,所以不建议这样做。

    您可以使用 Scala 模式匹配来完成此操作,方法是在字符串上调用 .toList 将其转换为 List[Char]。然后你的部分namedomainzone 也将是 List[Char],使用 .mkString 将它们转回字符串。虽然我不确定这有多有效。

    我已经针对各种用例使用基本字符串操作(如 substring、indexOf 等)与正则表达式进行了基准测试,而正则表达式通常慢一两个。当然,正则表达式非常难以阅读。

    更新:最好的办法是使用解析器,无论是原生 Scala 还是 Parboiled2

    【讨论】:

    • 什么?你每次都重建正则表达式吗?正则表达式的重点是它们创建了可以非常有效地与字符串匹配的“机器”。此外,将正则表达式用于非常小的检查没有意义,但对于更复杂的匹配,我希望能大大节省效率,尤其是当输入通过的数量增加时。
    • @KenoguLabz 不,正则表达式构造超出了基准。当我上次参加 Scala eXchange 会议时,我看到一个演讲声称使用解析器(或原生 Scala StringOps)通常快 100 到 1000 倍。显然,如果一个正则表达式构建得不好,速度差异可能会更大(查找回溯regular-expressions.info/catastrophic.html)。我自己的基准测试通常是在包含数十亿条记录的真实数据上执行的。
    • @samthebest 我对此非常感兴趣,因为我发现正则表达式是一种无法维护的语言。 scala Parsers 如何优于已编译的正则表达式自动机?你对此有多确定,或者你能详细说明什么情况?裸骨StringOps 当然级别太低,无法维护代码......对于那些特定方法适合您的小型临时需求的情况而言,这不太可能是一个好的选择。想在此处和/或在答案中详细说明?
    • @matt 使用解析器的三个主要好处是 IMO (a) 可以选择使用正则表达式样式语法或全名版本,例如zeroOrMore+,提高可读性,(b) 静态完整类型,例如+ 给出了 List,然后您可以对其进行映射、转换等操作,这也意味着 IDE 将语法高亮显示它 (c) parboiled2 是部分基于宏的编译器,因此可以比正则表达式快得多。 github.com/sirthias/parboiled2#example
    • 谢谢,对我来说,这些优势一开始就很明显。但我发现这些可以解决速度方面的问题:github.com/sirthias/…github.com/sirthias/…。要是他们能被信任就好了,我似乎记得看到人们说半熟很慢。
    猜你喜欢
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多