括号中斯卡拉匹配 - 功能方法(Parentheses matching in Scala — fu

2019-09-16 07:44发布

比方说,我想分析各种开启和关闭括号中的字符串(我用括号中的标题,因为我相信这是比较常见的 - 的问题仍然是相同的),所以我得到的名单分开所有的更高的水平。

鉴于:

[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]

我想要:

List("[hello:=[notting],[hill]]", "[3.4(4.56676|5.67787)]", "[the[hill[is[high]]not]]")

我这样做的方法是通过计算打开和关闭括号并添加到列表中时,我让我的计数器为0。但是,我有一个丑陋的命令性代码。 你可以假设的是,原来的字符串,完全形成了。

我的问题是:什么是这个问题的一个很好的功能性的方法吗?

注:我已经想到了使用了...产量结构的,但考虑到使用计数器我不能得到一个简单的条件(我必须条件只是用于更新计数器为好),我不知道我怎么会用这个建立在这种情况下。

Answer 1:

使用Scala的解析器组合库快速的解决方案:

import util.parsing.combinator.RegexParsers

object Parser extends RegexParsers {
  lazy val t = "[^\\[\\]\\(\\)]+".r

  def paren: Parser[String] =
    ("(" ~ rep1(t | paren) ~ ")" |
     "[" ~ rep1(t | paren) ~ "]") ^^ {
      case o ~ l ~ c => (o :: l ::: c :: Nil) mkString ""
    }

  def all = rep(paren)

  def apply(s: String) = parseAll(all, s)
}

检查它在REPL:

scala> Parser("[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]")
res0: Parser.ParseResult[List[String]] = [1.72] parsed: List([hello:=[notting],[hill]], [3.4(4.56676|5.67787)], [the[hill[is[high]]not]])


Answer 2:

关于什么:

def split(input: String): List[String] = {
  def loop(pos: Int, ends: List[Int], xs: List[String]): List[String] =
    if (pos >= 0)
      if ((input charAt pos) == ']') loop(pos-1, pos+1 :: ends, xs)
      else if ((input charAt pos) == '[')
        if (ends.size == 1) loop(pos-1, Nil, input.substring(pos, ends.head) :: xs)
        else loop(pos-1, ends.tail, xs)
      else loop(pos-1, ends, xs)
    else xs
  loop(input.length-1, Nil, Nil)
}

scala> val s1 = "[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]"
s1: String = [hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]

scala> val s2 = "[f[sad][add]dir][er][p]"
s2: String = [f[sad][add]dir][er][p]

scala> split(s1) foreach println
[hello:=[notting],[hill]]
[3.4(4.56676|5.67787)]
[the[hill[is[high]]not]]

scala> split(s2) foreach println
[f[sad][add]dir]
[er]
[p]


Answer 3:

鉴于您的要求计算括号似乎完全罚款。 你会怎么做,在一个功能呢? 您可以在状态各地明确传递。

所以,首先我们定义的状态,其积聚在结果blocks或者连接下一个block并跟踪深度:

case class Parsed(blocks: Vector[String], block: String, depth: Int)

然后我们编写处理返回的下一个状态的纯函数。 但愿,我们只要仔细看一下这一功能,并确保它是正确的。

def nextChar(parsed: Parsed, c: Char): Parsed = {
  import parsed._
  c match {
    case '[' | '(' => parsed.copy(block = block + c,
                                  depth = depth + 1)
    case ']' | ')' if depth == 1 
                   => parsed.copy(blocks = blocks :+ (block + c),
                                  block = "",
                                  depth = depth - 1)
    case ']' | ')' => parsed.copy(block = block + c,
                                  depth = depth - 1)
    case _         => parsed.copy(block = block + c)
  }
}

然后,我们只是使用了foldLeft处理与初始状态的数据:

val data = "[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]"
val parsed = data.foldLeft(Parsed(Vector(), "", 0))(nextChar) 
parsed.blocks foreach println

返回:

[hello:=[notting],[hill]]
[3.4(4.56676|5.67787)]
[the[hill[is[high]]not]]


Answer 4:

你有一个丑陋的当务之急的解决方案,那么为什么不使一个好看吗? :)

这是huynhjl的解决方案的一个必要的翻译,但只是发布表明,有时候必须是简洁,也许更容易理解。

  def parse(s: String) = {
    var res = Vector[String]()
    var depth = 0
    var block = ""
    for (c <- s) {
      block += c
      c match {
        case '[' => depth += 1
        case ']' => depth -= 1
                    if (depth == 0) {
                      res :+= block
                      block = ""
                    }
        case _   =>
      }
    }
    res
  }


Answer 5:

尝试这个:

val s = "[hello:=[notting],[hill]][3.4(4.56676|5.67787)][the[hill[is[high]]not]]"
s.split("]\\[").toList

收益:

List[String](
  [hello:=[notting],[hill],
  3.4(4.56676|5.67787),
  the[hill[is[high]]not]]
)


文章来源: Parentheses matching in Scala — functional approach