【问题标题】:case matching strings based on an algorithm. Which algorithm should I use?基于算法的大小写匹配字符串。我应该使用哪种算法?
【发布时间】:2017-07-12 22:51:04
【问题描述】:

我需要在我的代码中将电视收视率(用于电视节目)转换为该收视率的案例对象。因此我有一个这样的案例匹配:

def fromString(s: String): Option[TvRating] = s.toLowerCase match {
  case "tvy" | "tv-y" | "tv y" | "y" => Some(tvY)
  case "tvg" | "tv-g" | "tv g" | "g" => Some(tvG)
  case "tvpg" | "tv-pg" | "tv pg" | "pg" => Some(tvG)
  case "tv14" | "tv-14" | "tv 14" | "14" => Some(tv14)
  case "tvma" | "tv-ma" | "tv ma" | "ma" => Some(tvMA)
  case _ => Some(noTvRating)
}

如您所见,我正在尝试匹配每个评级的所有排列,这很麻烦,并且仍然不考虑诸如“tv.14”或“成熟观众”之类的内容。

有没有像 soundX 这样的算法,但对于像这些评级这样的代码,我可以作为最后的手段使用。然后我的代码将如下所示:

def fromString(s: String): Option[TvRating] = s.toLowerCase match {
  case "tvy" | "tv-y" | fancyAlgo(s, "tv-y") => Some(tvY)
  case "tvg" | "tv-g" | fancyAlgo(s, "tv-g") => Some(tvG)
  case "tvpg" | "tv-pg" | fancyAlgo(s, "tv-pg") => Some(tvG)
  case "tv14" | "tv-14" | fancyAlgo(s, "tv-14") => Some(tv14)
  case "tvma" | "tv-ma" | fancyAlgo(s, "tv-ma") => Some(tvMA)
  case _ => Some(noTvRating)
}

或者我可以使这些匹配更健壮的任何其他建议。由于 tv-g 不是“狗”或“马”之类的词,因此我不能基于音频或类似发音的词。

这是评级的一个例子。还有其他比赛。这是星级评分的另一个示例(如烂番茄的电影评分)

def fromString(s: String): Option[StarRating] = s.toLowerCase match {
  case "1" | "one star" | "one stars" => Some(oneStar)
  case "1.5" | "1.5 stars" | "one and a half stars" => Some(oneAndHalfStar)
  case "2" | "2 stars" | "two stars" => Some(twoStars)
  case "2.5" | "2.5 stars" | "two and a half stars" => Some(twoAndHalfStars)
  case "3" | "3 stars" | "three stars" => Some(threeStars)
  case "3.5" | "3.5 stars" | "three and a half stars" => Some(threeAndHalfStars)
  case "4" | "4 stars" | "four stars" => Some(fourStars)
  case _ => Some(noStars)
}

干杯!

【问题讨论】:

  • 模糊字符串是否与我正在寻找的匹配?
  • 我明白你的意思,但我认为(一般来说)你要求几乎不可能 - 匹配任何意味着(比如)“pg”但没有说明规则意味着“ pg”。这不是模糊字符串匹配,因为 匹配的内容并不明显,如果您可以详细说明可以匹配的内容,请说“tv-14”(例如,“十四”是否应该匹配? ) 那么也许可以做点什么
  • Option[] 类型的全部意义在于它可能None。为什么您的示例没有 None 条件?
  • 好问题,我会检查这个返回值是否在某个地方结束。或者,如果其他任何地方的任何这种风格的代码都在使用 None 。有些可能,并且为了保持一致性(例如,将它们放在列表中以映射时),最好在此处使用 Option。

标签: algorithm scala pattern-matching string-matching


【解决方案1】:

Go 数据驱动:

val ratings = scala.collection.mutable.Map[String, String]() withDefaultValue "noTVRating"

type TvRating = String

def addRatingStyle(base:String, result:String) = {
  val suffix = base.stripPrefix("tv")
  ratings += ("tv"+suffix->result)
  ratings += ("tv-"+suffix->result)
  ratings += ("tv "+suffix->result)
  ratings += (suffix->result)
}

addRatingStyle("tvy", "tvy")
addRatingStyle("tvg", "tvg")
addRatingStyle("tvpg", "tvpg")
addRatingStyle("tv14", "tv14")
addRatingStyle("tvma", "tvma")


def fromString(s: String): Option[TvRating] = Some(ratings(s.toLowerCase)) 

【讨论】:

  • 赞成因为有趣的解决方案,但没有解决我的匹配问题。问题是我不知道前缀是否总是“”、“-”或“”。否则,我的原始匹配就可以正常工作,而无需为程序员添加上述上下文重载。虽然很有创意,但它不使用算法来找到“最佳”匹配。
【解决方案2】:

使用case objects 通过unapply 方法定义您的个人评级。一个简单的正则表达式可能会处理其余部分:

sealed trait TVRating

case object Youth extends TVRating {
  def unapply(s: String): Option[TVRating] = {
    //insert fancier match logic here...
    if( s.matches("tv.*y") || s.equals("y")) {
      Some(Youth)
    } else {
      None
    }
  }
}

case object General extends TVRating {
  def unapply(s: String): Option[TVRating] = {
    //insert fancier match logic here...
    if( s.matches("tv.*g")) {
      Some(Youth)
    } else {
      None
    }
  }
}

object Main extends App {

  override def main(args: Array[String]) = {
    "tv.y" match {
        case Youth(s) => println("Youth")
        case General(s) => println("General")
        case _ => println("Unknown")
    }
  }
}

【讨论】:

  • 我总是忘记取消申请。这是一个很酷的解决方案!我看到的唯一缺点是正则表达式并没有放在一个地方供我查看或添加。问题:def main 前面的覆盖在做什么?
  • 这个答案说明了为什么我在上面评论说 OP 正在寻找几乎不可能的东西(虽然这不是答案本身的问题)。请注意,General 也匹配 PG。 Soundex 工作的原因是从单词的拼写到声音的映射相当容易理解,尽管是语音(尽管即使那样,由于通常奇怪的英语问题,也会有很多误报和误报)。人们倾向于将 Soundex 用于一种“足够好”的匹配,而不是“必须完全分类到正确的存储桶”,而这正是这里所需要的。
猜你喜欢
  • 2015-08-05
  • 1970-01-01
  • 2011-09-16
  • 2014-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
相关资源
最近更新 更多