在Scala中解析命令行参数的最佳方法是什么? 我个人更喜欢一些不需要外部罐子的轻量级的东西。

相关:

我如何解析Java中的命令行参数? c++有哪些参数解析器库? 在c#中解析命令行参数的最佳方法


当前回答

这是我做的。它返回一个map和list的元组。列表是用于输入的,就像输入文件名一样。Map用于开关/选项。

val args = "--sw1 1 input_1 --sw2 --sw3 2 input_2 --sw4".split(" ")
val (options, inputs) = OptParser.parse(args)

将返回

options: Map[Symbol,Any] = Map('sw1 -> 1, 'sw2 -> true, 'sw3 -> 2, 'sw4 -> true)
inputs: List[Symbol] = List('input_1, 'input_2)

开关可以是“——t”,x将被设置为true,或者“——x 10”,x将被设置为“10”。其他的都将在列表中结束。

object OptParser {
  val map: Map[Symbol, Any] = Map()
  val list: List[Symbol] = List()

  def parse(args: Array[String]): (Map[Symbol, Any], List[Symbol]) = _parse(map, list, args.toList)

  private [this] def _parse(map: Map[Symbol, Any], list: List[Symbol], args: List[String]): (Map[Symbol, Any], List[Symbol]) = {
    args match {
      case Nil => (map, list)
      case arg :: value :: tail if (arg.startsWith("--") && !value.startsWith("--")) => _parse(map ++ Map(Symbol(arg.substring(2)) -> value), list, tail)
      case arg :: tail if (arg.startsWith("--")) => _parse(map ++ Map(Symbol(arg.substring(2)) -> true), list, tail)
      case opt :: tail => _parse(map, list :+ Symbol(opt), tail)
    }
  }
}

其他回答

还有JCommander(免责声明:我创建了它):

object Main {
  object Args {
    @Parameter(
      names = Array("-f", "--file"),
      description = "File to load. Can be specified multiple times.")
    var file: java.util.List[String] = null
  }

  def main(args: Array[String]): Unit = {
    new JCommander(Args, args.toArray: _*)
    for (filename <- Args.file) {
      val f = new File(filename)
      printf("file: %s\n", f.getName)
    }
  }
}

如何在没有外部依赖的情况下解析参数。好问题!你可能会对picocli感兴趣。

Picocli是专门为解决问题而设计的:它是一个文件中的命令行解析框架,因此可以以源代码形式包含它。这允许用户运行基于picocli的应用程序,而不需要将picocli作为外部依赖项。

它通过注释字段来工作,因此您只需编写很少的代码。快速总结:

强类型的一切-命令行选项以及位置参数 支持POSIX集群短选项(因此它处理<命令> -xvfInputFile以及<命令> -x -v -f InputFile) 一个允许最小、最大和可变数量参数的arity模型,例如,“1..3 . . *”、“5” 流畅和紧凑的API,以尽量减少样板客户端代码 子命令 使用ANSI颜色的帮助

使用帮助消息很容易使用注释进行定制(无需编程)。例如:

(源)

我忍不住又加了一张截图来展示使用帮助信息的类型。使用帮助是应用程序的门面,所以要有创意,玩得开心!

声明:我创建了picocli。欢迎反馈或提问。它是用java编写的,但如果在scala中使用它有任何问题,请告诉我,我会尝试解决它。

scala-optparse-applicative

我认为Scala -optparse-applicative是Scala中功能最强大的命令行解析器库。

https://github.com/bmjames/scala-optparse-applicative

我喜欢joslinm的slide()方法,而不是可变的vars;)这里有一个不可改变的方法:

case class AppArgs(
              seed1: String,
              seed2: String,
              ip: String,
              port: Int
              )
object AppArgs {
  def empty = new AppArgs("", "", "", 0)
}

val args = Array[String](
  "--seed1", "akka.tcp://seed1",
  "--seed2", "akka.tcp://seed2",
  "--nodeip", "192.167.1.1",
  "--nodeport", "2551"
)

val argsInstance = args.sliding(2, 1).toList.foldLeft(AppArgs.empty) { case (accumArgs, currArgs) => currArgs match {
    case Array("--seed1", seed1) => accumArgs.copy(seed1 = seed1)
    case Array("--seed2", seed2) => accumArgs.copy(seed2 = seed2)
    case Array("--nodeip", ip) => accumArgs.copy(ip = ip)
    case Array("--nodeport", port) => accumArgs.copy(port = port.toInt)
    case unknownArg => accumArgs // Do whatever you want for this case
  }
}

这在很大程度上是我对同一主题的Java问题的答案的无耻克隆。事实证明,JewelCLI是scala友好的,因为它不需要JavaBean样式的方法来获得自动参数命名。

JewelCLI是一个scala友好的Java库,用于命令行解析,生成干净的代码。它使用带有注解的代理接口来动态地为命令行参数构建类型安全的API。

一个参数接口Person.scala的例子:

import uk.co.flamingpenguin.jewel.cli.Option

trait Person {
  @Option def name: String
  @Option def times: Int
}

参数接口Hello.scala的用法示例:

import uk.co.flamingpenguin.jewel.cli.CliFactory.parseArguments
import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException

object Hello {
  def main(args: Array[String]) {
    try {
      val person = parseArguments(classOf[Person], args:_*)
      for (i <- 1 to (person times))
        println("Hello " + (person name))
    } catch {
      case e: ArgumentValidationException => println(e getMessage)
    }
  }
}

将上述文件的副本保存到一个目录中,并将JewelCLI 0.6 JAR下载到该目录中。

在Linux/Mac OS X/etc / Bash中编译并运行示例:

scalac -cp jewelcli-0.6.jar:. Person.scala Hello.scala
scala -cp jewelcli-0.6.jar:. Hello --name="John Doe" --times=3

在Windows命令提示符中编译并运行示例:

scalac -cp jewelcli-0.6.jar;. Person.scala Hello.scala
scala -cp jewelcli-0.6.jar;. Hello --name="John Doe" --times=3

运行该示例应该产生以下输出:

Hello John Doe
Hello John Doe
Hello John Doe