从Scala方式读取同一行的多个输入

Tre*_*vor 9 string parsing scala input

我试图用来readInt()从同一行读取两个整数,但这不是它的工作原理.

val x = readInt()
val y = readInt()
Run Code Online (Sandbox Code Playgroud)

输入1 727我在运行时得到以下异常:

Exception in thread "main" java.lang.NumberFormatException: For input string: "1 727"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:231)
    at scala.collection.immutable.StringOps.toInt(StringOps.scala:31)
    at scala.Console$.readInt(Console.scala:356)
    at scala.Predef$.readInt(Predef.scala:201)
    at Main$$anonfun$main$1.apply$mcVI$sp(Main.scala:11)
    at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:75)
    at Main$.main(Main.scala:10)
    at Main.main(Main.scala)
Run Code Online (Sandbox Code Playgroud)

我通过使用程序工作,readf但对我来说似乎很尴尬和丑陋:

  val (x,y) = readf2("{0,number} {1,number}")
  val a = x.asInstanceOf[Int]
  val b = y.asInstanceOf[Int]
  println(function(a,b))
Run Code Online (Sandbox Code Playgroud)

有人建议我只使用Java的Scanner类,(Scanner.nextInt())但是在Scala中有一个很好的惯用方法吗?

编辑:我的解决方案遵循范例的例子:

val Array(a,b) = readLine().split(" ").map(_.toInt)
Run Code Online (Sandbox Code Playgroud)

后续问题:如果字符串中有多种类型,您将如何提取它?(说一个单词,一个int和一个百分比作为Double)

Lui*_*hys 6

如果你的意思是如何转换val s = "Hello 69 13.5%"成一个(String, Int, Double)最明显的方式

val tokens = s.split(" ")
(tokens(0).toString, 
 tokens(1).toInt, 
 tokens(2).init.toDouble / 100)
 // (java.lang.String, Int, Double) = (Hello,69,0.135)
Run Code Online (Sandbox Code Playgroud)

或者如上所述,您可以使用正则表达式进行匹配:

val R = """(.*) (\d+) (\d*\.?\d*)%""".r
s match {
  case R(str, int, dbl) => (str, int.toInt, dbl.toDouble / 100)
}
Run Code Online (Sandbox Code Playgroud)

如果你实际上并不知道String中将包含哪些数据,那么可能没有太多理由将它从String转换为它所代表的类型,因为你如何使用可能是a的东西String并且可能是在Int?不过,你可以这样做:

val int = """(\d+)""".r
val pct = """(\d*\.?\d*)%""".r

val res = s.split(" ").map {
  case int(x) => x.toInt
  case pct(x) => x.toDouble / 100
  case str => str
} // Array[Any] = Array(Hello, 69, 0.135)
Run Code Online (Sandbox Code Playgroud)

现在要做任何有用的事情,你需要按类型匹配你的值:

res.map {
  case x: Int => println("It's an Int!")
  case x: Double => println("It's a Double!")
  case x: String => println("It's a String!")
  case _ => println("It's a Fail!")
}
Run Code Online (Sandbox Code Playgroud)

或者如果你想更进一步,你可以定义一些提取器来为你做转换:

abstract class StringExtractor[A] {
  def conversion(s: String): A
  def unapply(s: String): Option[A] = try { Some(conversion(s)) } 
                                      catch { case _ => None }
}

val intEx = new StringExtractor[Int] { 
  def conversion(s: String) = s.toInt 
}
val pctEx = new StringExtractor[Double] { 
   val pct = """(\d*\.?\d*)%""".r
   def conversion(s: String) = s match { case pct(x) => x.toDouble / 100 } 
}
Run Code Online (Sandbox Code Playgroud)

并使用:

"Hello 69 13.5%".split(" ").map {
  case intEx(x) => println(x + " is Int: "    + x.isInstanceOf[Int])
  case pctEx(x) => println(x + " is Double: " + x.isInstanceOf[Double])
  case str      => println(str)
}
Run Code Online (Sandbox Code Playgroud)

版画

Hello
69 is Int: true
0.135 is Double: true
Run Code Online (Sandbox Code Playgroud)

当然,您可以使分配器匹配您想要的任何东西(货币助记符,名称用'J',URL)并返回您想要的任何类型.如果不是StringExtractor[A]你做的话,你也不仅限于匹配字符串Extractor[A, B].


par*_*tic 5

您可以读取整个行,使用空格拆分它,然后将每个元素(或您想要的那个)转换为整数:

scala> "1 727".split(" ").map( _.toInt )
res1: Array[Int] = Array(1, 727)
Run Code Online (Sandbox Code Playgroud)

对于大多数复杂的输入,您可以查看解析器组合器.

  • 对于中等复杂的输入,您可以使用正则表达式匹配器. (3认同)