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

相关:

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


当前回答

对于相对简单的配置,我喜欢滑动参数。

var name = ""
var port = 0
var ip = ""
args.sliding(2, 2).toList.collect {
  case Array("--ip", argIP: String) => ip = argIP
  case Array("--port", argPort: String) => port = argPort.toInt
  case Array("--name", argName: String) => name = argName
}

其他回答

还有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)
    }
  }
}

我再多说一点。我用一行简单的代码解决了这个问题。我的命令行参数是这样的:

input--hdfs:/path/to/myData/part-00199.avro output--hdfs:/path/toWrite/Data fileFormat--avro option1--5

这将通过Scala的本机命令行功能(从App或main方法)创建一个数组:

Array("input--hdfs:/path/to/myData/part-00199.avro", "output--hdfs:/path/toWrite/Data","fileFormat--avro","option1--5")

然后我可以使用这一行来解析出默认的args数组:

val nArgs = args.map(x=>x.split("--")).map(y=>(y(0),y(1))).toMap

它创建了一个与命令行值关联的名称映射:

Map(input -> hdfs:/path/to/myData/part-00199.avro, output -> hdfs:/path/toWrite/Data, fileFormat -> avro, option1 -> 5)

然后,我可以在代码中访问命名参数的值,它们在命令行上出现的顺序不再相关。我意识到这相当简单,没有上面提到的所有高级功能,但在大多数情况下似乎足够了,只需要一行代码,并且不涉及外部依赖关系。

scala-optparse-applicative

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

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

我的方法基于上面的答案(来自dave4420),并试图通过使其更通用来改进它。

它返回所有命令行参数的映射[String,String] 你可以查询你想要的特定参数(例如使用.contains)或将值转换为你想要的类型(例如使用toInt)。

def argsToOptionMap(args:Array[String]):Map[String,String]= {
  def nextOption(
      argList:List[String], 
      map:Map[String, String]
    ) : Map[String, String] = {
    val pattern       = "--(\\w+)".r // Selects Arg from --Arg
    val patternSwitch = "-(\\w+)".r  // Selects Arg from -Arg
    argList match {
      case Nil => map
      case pattern(opt)       :: value  :: tail => nextOption( tail, map ++ Map(opt->value) )
      case patternSwitch(opt) :: tail => nextOption( tail, map ++ Map(opt->null) )
      case string             :: Nil  => map ++ Map(string->null)
      case option             :: tail => {
        println("Unknown option:"+option) 
        sys.exit(1)
      }
    }
  }
  nextOption(args.toList,Map())
}

例子:

val args=Array("--testing1","testing1","-a","-b","--c","d","test2")
argsToOptionMap( args  )

给:

res0: Map[String,String] = Map(testing1 -> testing1, a -> null, b -> null, c -> d, test2 -> null)

另一个库:scarg