57

Scala Combinators でパーサーを作成しています。すばらしい。私が最終的に得たのは、絡み合ったケースクラスの長いリストですClassDecl(Complex,List(VarDecl(Real,float), VarDecl(Imag,float)))。読みやすくするために、これらのようなケースクラスをツリ​​ーのような方法で印刷する良い方法があるかどうか疑問に思っていました..? (または他の形式のPretty Print )

ClassDecl
  name = Complex
  fields =
  - VarDecl
      name = Real
      type = float
  - VarDecl
      name = Imag
      type = float

↑こんな感じで終わりたい

編集:ボーナス質問

パラメータの名前を表示する方法もあります..? のように: ClassDecl(name=Complex, fields=List( ... )?

4

11 に答える 11

38

sextという名前の小さな拡張ライブラリをチェックしてください。この 2 つの関数は、そのような目的のために正確にエクスポートされます。

あなたの例でそれを使用する方法は次のとおりです。

object Demo extends App {

  import sext._

  case class ClassDecl( kind : Kind, list : List[ VarDecl ] )
  sealed trait Kind
  case object Complex extends Kind
  case class VarDecl( a : Int, b : String )


  val data = ClassDecl(Complex,List(VarDecl(1, "abcd"), VarDecl(2, "efgh")))
  println("treeString output:\n")
  println(data.treeString)
  println()
  println("valueTreeString output:\n")
  println(data.valueTreeString)

}

以下は、このプログラムの出力です。

treeString output:

ClassDecl:
- Complex
- List:
| - VarDecl:
| | - 1
| | - abcd
| - VarDecl:
| | - 2
| | - efgh

valueTreeString output:

- kind:
- list:
| - - a:
| | | 1
| | - b:
| | | abcd
| - - a:
| | | 2
| | - b:
| | | efgh
于 2013-03-30T13:16:46.933 に答える
13

com.lihaoyi.pprint ライブラリを使用します。

libraryDependencies += "com.lihaoyi" %% "pprint" % "0.4.1"

val data = ...

val str = pprint.tokenize(data).mkString
println(str)

幅、高さ、インデント、および色を構成することもできます。

pprint.tokenize(data, width = 80).mkString

ドキュメント: https://github.com/com-lihaoyi/PPrint

于 2016-10-14T15:11:25.327 に答える
7

パーサー コンビネーターと同様に、Scala には標準ライブラリにプリティ プリンター コンビネーターが既に含まれています。(: このライブラリは Scala 2.11 で非推奨になりました。同様のプリティ プリンティング ライブラリはkiamaオープン ソース プロジェクトの一部です)。

「リフレクション」を行うソリューションが必要な場合、またはプリンターを明示的に構築したい場合は、質問でそれを明確に言っているわけではありません。(ただし、「ボーナスの質問」は、おそらく「反射的な」ソリューションが必要であることを示唆しています)

とにかく、単純な Scala ライブラリを使用してシンプルできれいなプリンターを開発したい場合は、ここにあります。次のコードは REPLable です。

case class VarDecl(name: String, `type`: String)
case class ClassDecl(name: String, fields: List[VarDecl])

import scala.text._
import Document._

def varDoc(x: VarDecl) =
  nest(4, text("- VarDecl") :/:
    group("name = " :: text(x.name)) :/:
    group("type = " :: text(x.`type`))
  )

def classDoc(x: ClassDecl) = {
  val docs = ((empty:Document) /: x.fields) { (d, f) => varDoc(f) :/: d }
  nest(2, text("ClassDecl") :/:
    group("name = " :: text(x.name)) :/:
    group("fields =" :/: docs))
}

def prettyPrint(d: Document) = {
  val writer = new java.io.StringWriter
  d.format(1, writer)
  writer.toString
}

prettyPrint(classDoc(
  ClassDecl("Complex", VarDecl("Real","float") :: VarDecl("Imag","float") :: Nil)
))

おまけの質問: プリンターを型クラスにラップして、構成可能性をさらに高めます。

于 2013-03-30T15:20:54.877 に答える
5

私が見つけた最も優れた、最も簡潔な「すぐに使える」エクスペリエンスは、Kiama pretty printing libraryを使用したものです。追加のコンビネータを使用せずにメンバー名を出力することはありませんが、import org.kiama.output.PrettyPrinter._; pretty(any(data))あなただけが素晴らしいスタートを切ることができます:

case class ClassDecl( kind : Kind, list : List[ VarDecl ] )
sealed trait Kind
case object Complex extends Kind
case class VarDecl( a : Int, b : String )

val data = ClassDecl(Complex,List(VarDecl(1, "abcd"), VarDecl(2, "efgh")))
import org.kiama.output.PrettyPrinter._

// `w` is the wrapping width. `1` forces wrapping all components.
pretty(any(data), w=1)

プロデュース:

ClassDecl (
    Complex (),
    List (
        VarDecl (
            1,
            "abcd"),
        VarDecl (
            2,
            "efgh")))

これは最も基本的な例にすぎないことに注意してください。Kiama PrettyPrinter は、インテリジェントなスペーシング、ライン ラッピング、ネスティング、およびグループ化のために特別に設計された豊富なコンビネータ セットを備えた非常に強力なライブラリです。ニーズに合わせて微調整するのは非常に簡単です。この投稿の時点で、SBT で以下を使用できます。

libraryDependencies += "com.googlecode.kiama" %% "kiama" % "1.8.0"
于 2015-07-09T13:04:36.943 に答える
4

リフレクションの使用

import scala.reflect.ClassTag
import scala.reflect.runtime.universe._

object CaseClassBeautifier  {
  def getCaseAccessors[T: TypeTag] = typeOf[T].members.collect {
    case m: MethodSymbol if m.isCaseAccessor => m
  }.toList

  def nice[T:TypeTag](x: T)(implicit classTag: ClassTag[T]) : String = {
    val instance = x.asInstanceOf[T]
    val mirror = runtimeMirror(instance.getClass.getClassLoader)
    val accessors = getCaseAccessors[T]
    var res = List.empty[String]
    accessors.foreach { z ⇒
      val instanceMirror = mirror.reflect(instance)
      val fieldMirror = instanceMirror.reflectField(z.asTerm)
      val s = s"${z.name} = ${fieldMirror.get}"
      res = s :: res
    }
    val beautified = x.getClass.getSimpleName + "(" + res.mkString(", ") + ")"
    beautified
  }
}
于 2016-02-21T13:23:25.750 に答える
0

選択したテスト フレームワークの AssertEquals で使用されているものと同じプリントを使用することをお勧めします。私はScalametaを 使用していましたが、うまくいきmunit.Assertions.munitPrint(clue: => Any): Stringました。ネストされたクラスをそれに渡すと、ツリー全体が適切なインデントで表示されます。

于 2021-09-27T18:50:28.103 に答える