斯卡拉条件积累

时间:2018-09-26 22:44:00

标签: scala

我正在尝试实现一个从字符串中提取“占位符”列表的函数。起始占位符和结束占位符的分隔符为$。我有一些想法如何使用var启用/禁用累积来实现它,我想做的就是在没有任何var的情况下实现它

对于像这样的字符串

val stringToParse = "ignore/me/$aaa$/once-again/ignore/me/$bbb$/still-to-be/ignored

结果应该是

Seq("aaa", "bbb")

有什么提示吗?

这是使用var的解决方案

import fiddle.Fiddle, Fiddle.println
import scalajs.js
import scala.collection.mutable.ListBuffer

@js.annotation.JSExportTopLevel("ScalaFiddle")
object ScalaFiddle {
  // $FiddleStart


  val stringToParse = "ignore/me/$aaa$/once-again/ignore/me/$bbb$/still-to-be/ignored"

  class StringAccumulator {

    val accumulator: ListBuffer[String] = new ListBuffer[String]
    val sb: StringBuilder = new StringBuilder("")
    var open:Boolean = false

    def next():Unit = {
      if (open) {
        accumulator.append(sb.toString)
        sb.clear
        open = false
      } else {
        open = true
      }
    }

    def accumulateIfOpen(charToAccumulate: Char):Unit = {
      if (open) sb.append(charToAccumulate)
    }

    def get(): Seq[String] = accumulator.toList
  }

  def getPlaceHolders(str: String): Seq[String] = {
    val sac = new StringAccumulator

    str.foreach(chr => {
      if (chr == '$') {
        sac.next()
      } else {
        sac.accumulateIfOpen(chr)
      }
    })

    sac.get
  }

  println(getPlaceHolders(stringToParse))
  // $FiddleEnd
}

2 个答案:

答案 0 :(得分:1)

这个解决方案够吗?

node->key

答案 1 :(得分:1)

我将向您介绍两种解决方案。首先是您所做的最直接的翻译。在Scala中,如果您听到单词accumulate,通常会翻译成foldreduce的变体。

def

 extractValues(s: String) =
  {
    //We can combine the functionality of your boolean and stringbuilder by using an Option
    s.foldLeft[(ListBuffer[String],Option[StringBuilder])]((new ListBuffer[String], Option.empty))
                  {
                    //As we fold through, we have the accumulated list, possibly a partially built String, and the current letter
                    case ((accumulator,sbOption),char) =>
                    {
                      char match
                      {
                        //This logic pretty much matches what you had, adjusted to work with the Option
                        case '$' =>
                        {
                          sbOption match
                          {
                            case Some(sb) =>
                            {
                              accumulator.append(sb.mkString)
                              (accumulator,None)
                            }
                            case None =>
                            {
                              (accumulator,Some(new StringBuilder))
                            }
                          }
                        }
                        case _ =>
                        {
                          sbOption.foreach(_.append(char))
                          (accumulator,sbOption)
                        }
                      }
                    }
                  }._1.map(_.mkString).toList
  }

但是,这似乎很复杂,因为听起来像是一个简单的任务。我们可以使用正则表达式,但是它们很吓人,因此请避免使用它们。实际上,经过一点思考,这个问题实际上变得非常简单。

 def extractValuesSimple(s: String)=
  {
    s.split('$').//split the string on the $ character
      dropRight(1).//Drops the rightmost item, to handle the case with an odd number of $
      zipWithIndex.filter{case (str, index) => index % 2 == 1}.//Filter out all of the even indexed items, which will always be outside of the matching $
      map{case (str, index) => str}.toList//Remove the indexes from the output
  }