【问题标题】:Pattern matching or how to further exploit operators for string matches in Scala?模式匹配或如何进一步利用运算符在 Scala 中进行字符串匹配?
【发布时间】:2011-11-13 10:12:00
【问题描述】:

通过 Scala 的模式匹配,我想确认的不仅是两个 Strings 相等,还想确认 String 是否以另一个开头、结尾或包含在另一个等中。

我尝试了案例类和提取器对象,都没有给我一个简洁的解决方案。所以我想出的解决方案如下:

class StrMatches(private val str: Option[String]) {

  def ^(prefix: String) = str.exists(_.startsWith(prefix))

  def §(suffix: String) = str.exists(_.endsWith(suffix))

  def %(infix: String) = str.exists(_.contains(infix))

  def ~(approx: String) = str.exists(_.equalsIgnoreCase(approx))

  def /(regex: scala.util.matching.Regex) = str.collect({ case regex() => true }).isDefined

  def °(len: Int) = str.exists(_.length == len)

  def °°(len: (Int, Int)) = str.exists(a => a.length >= len._1 && a.length <= len._2)

  def `\\s*` = str.exists(_.trim.isEmpty)

  override def toString = str.mkString

}

object StrMatches {

  implicit def apply(x: Str) = new StrMatches(x)

  def unapply(x: StrMatches) = x.str

  implicit def unwrap(x: StrMatches) = x.toString

}

使用StrMatches 类的客户端可能如下所示:

object TestApp extends App {
  val str = "foobar"
  val strMatches = StrMatches(str)
  if (strMatches ^ "foo") {
    println(strMatches)
  }
  if (strMatches § "bar") {
    println(strMatches)
  }
  if (strMatches % "ob") {
    println(strMatches)
  }
}

相对于写作:

object TestApp extends App {
  val str: String = null // Just as an illustration for Scala interfacing Java.
  if (str != null) {
    if (str.startsWith("foo")) {
      println(str)
    }
    if (strMatches.endsWith("bar")) {
      println(str)
    }
    if (strMatches.contains("ob")) {
      println(strMatches)
    }
  }
}

您会想出什么样的解决方案?

【问题讨论】:

  • 这是一个非常开放的讨论。这根本不是一个问题。在 IRC 频道或 scala-lang.org/node/1707 的 Scala 邮件列表中,这可能会更好。
  • 我在 Scala-2.9.0.1 中收到问号 final case class StrMatches (str: ?[Str]) { 的错误:“StrMatches.scala:1: error: not found: type ?”
  • @user unknown,Scala 标识符可以是任何符号集合。它可能被定义为:trait ?[A]
  • 我不是很清楚,为什么你不使用String,而是使用Option[String],而不是Option,而是使用?[String],而不是String,但是一个Str。因此,您想要达到的目标以及问题出在哪里会很混乱。 s.startsWith ("foo")m ^ "foo" 长得多,但我不需要字典就能知道 m ^ "foo" 是什么意思。我的印象是,Str, ?, Option ... 不是你的重点,而且是理解问题的不必要的镇流器 - 如果主要问题得到解决,也许很方便 - 也就是说,你经常有模式,并且喜欢执行对同一模式进行多次检查?
  • 是的,我认为是这样的——我的问题是,你想要达到的开放目标是什么?节省 4 次击键?尝试时髦的名字?编写 DSL?

标签: scala operators pattern-matching string-comparison comparison-operators


【解决方案1】:

你可以使用正则表达式。然后你可以使用模式匹配(我认为这是你问题的初衷):

object TestApp extends App {
    val str = "foobar"

    val StartsWithFooRE = """^foo.*""".r
    val EndsWithBarRE = """.*bar$""".r
    val ContainsBoRE = """.*bo.*""".r

    str match {
        case StartsWithFooRE() => println(str)
        case EndsWithBarRE() => println(str)
        case ContainsBoRE() => println(str)
        case _ =>
    }
}

为了更方便,你可以定义一个带有工厂方法的对象来构造正则表达式。但是,由于模式匹配的工作原理,您仍然需要在匹配之外定义表达式:

import scala.util.matching.Regex

object RegexFactory {
    def startsWith(str: String) = new Regex("^%s.*" format str)
    def endsWith(str: String) = new Regex(".*%s$" format str)
    def contains(str: String) = new Regex(".*%s.*" format str)
}


object TestApp extends App {    
    val str = "foobar"

    import RegexFactory._

    val StartsWithFooRE = startsWith("foo")
    val EndsWithBarRE = endsWith("bar")
    val ContainsBoRE = contains("bo")

    str match {
        case StartsWithFooRE() => println(str)
        case EndsWithBarRE() => println(str)
        case ContainsBoRE() => println(str)
        case _ =>
    }
}

【讨论】:

  • 我现在从discussion on chat 看到这个问题更多的是关于编写 DSL 而不是模式匹配。尽管如此,我在这个过程中学到了一些关于 Scala 和 Regex 的东西,所以我留下答案,以防其他人发现它有用。
  • 我实际上想要从java.lang.String 进行非常基本的字符串比较,如startsWithendsWithcontains 等来执行工作,而不是在之前构建正则表达式解析树匹配它。但是赋予每个运算符方法的符号名称应该类似于正则表达式的相应元字符,如startsWith := ^、endsWith := § 等。
猜你喜欢
  • 2018-06-04
  • 1970-01-01
  • 2016-01-08
  • 1970-01-01
  • 2013-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多