2012-03-03 3 views
39

私はスカラ文字列を持っていると仮定し、その中からダブルを解析しようとします。Scala StringがDoubleとして解析可能かどうかを調べる方法は?

私はtoDoubleに電話して、これが失敗した場合はjava num形式の例外をキャッチすることができますが、これを行うにはよりクリーンな方法がありますか?たとえば、Option[Double]を返すparseDouble関数があった場合、これは修飾されます。

標準ライブラリに既に存在し、間違った場所で探しているだけの場合は、これを自分のコードに入れたくありません。

ご協力いただきありがとうございます。

答えて

42

それとも

def parseDouble(s: String) = try { Some(s.toDouble) } catch { case _ => None } 

ファンシーバージョン:

case class ParseOp[T](op: String => T) 
implicit val popDouble = ParseOp[Double](_.toDouble) 
implicit val popInt = ParseOp[Int](_.toInt) 
// etc. 
def parse[T: ParseOp](s: String) = try { Some(implicitly[ParseOp[T]].op(s)) } 
            catch {case _ => None} 

scala> parse[Double]("1.23") 
res13: Option[Double] = Some(1.23) 

scala> parse[Int]("1.23") 
res14: Option[Int] = None 

scala> parse[Int]("1") 
res15: Option[Int] = Some(1) 
+3

'_ 'だけでなく、' NonFatal(_) 'を実際にキャッチする必要があります。 – rightfold

+1

'Try'関数を使うべきです。 See @Jeff Schwabの答え。 – Moebius

6

これはScalaだけでなく、基本的なJavaの場合でも同様です。ここで

は、しかし、例外せず、それ ないピースコードです:

def parseDouble(s: String)(implicit nf: NumberFormat) = { 
    val pp = new ParsePosition(0) 
    val d = nf.parse(s, pp) 
    if (pp.getErrorIndex == -1) Some(d.doubleValue) else None 
} 

使用法:

implicit val formatter = NumberFormat.getInstance(Locale.ENGLISH) 

Console println parseDouble("184.33") 
Console println parseDouble("hello, world") 
10

util.control.Exception.catchingを使用すると、Eitherタイプが返されます。したがって、次を使用して

は左NumberFormatExceptionラッピングまたは右Double

import util.control.Exception._ 

catching(classOf[NumberFormatException]) either "12.W3".toDouble 
28

Scalaz包装返すタイプValidation[NumberFormatException, Double]の値を与えるString Sに拡張メソッドparseDoubleを、提供します。

scala> "34.5".parseDouble 
res34: scalaz.Validation[NumberFormatException,Double] = Success(34.5) 

scala> "34.bad".parseDouble 
res35: scalaz.Validation[NumberFormatException,Double] = Failure(java.lang.NumberFormatException: For input string: "34.bad") 

必要に応じてOptionに変換できます。

scala> "34.bad".parseDouble.toOption 
res36: Option[Double] = None 
+0

これは、 'Try()'でラップされたデフォルトのライブラリ実装と比較してどのようにパフォーマンスが向上しますか? – NightWolf

+0

@NightWolf、私がこの答えを書いた時点で「試行」は存在しませんでした。 :-)この文脈では、両方のアプローチが同じように動作し、パフォーマンスは同じでなければなりません。 – missingfaktor

+0

@NightWolf、私はScalazが以来、 'Validation'をやめてしまったと思います。私は間違っている可能性があります。私はしばらくそれを使用していません。 – missingfaktor

5

残念ながら、これは標準ライブラリにはありません。

class SafeParsePrimitive(s: String) { 
    private def nfe[T](t: => T) = { 
    try { Some(t) } 
    catch { case nfe: NumberFormatException => None } 
    } 
    def booleanOption = s.toLowerCase match { 
    case "yes" | "true" => Some(true) 
    case "no" | "false" => Some(false) 
    case _ => None 
    } 
    def byteOption = nfe(s.toByte) 
    def doubleOption = nfe(s.toDouble) 
    def floatOption = nfe(s.toFloat) 
    def hexOption = nfe(java.lang.Integer.valueOf(s,16)) 
    def hexLongOption = nfe(java.lang.Long.valueOf(s,16)) 
    def intOption = nfe(s.toInt) 
    def longOption = nfe(s.toLong) 
    def shortOption = nfe(s.toShort) 
} 
implicit def string_parses_safely(s: String) = new SafeParsePrimitive(s) 
17
scala> import scala.util.Try 
import scala.util.Try 

scala> def parseDouble(s: String): Option[Double] = Try { s.toDouble }.toOption 
parseDouble: (s: String)Option[Double] 

scala> parseDouble("3.14") 
res0: Option[Double] = Some(3.14) 

scala> parseDouble("hello") 
res1: Option[Double] = None 
1
私は通常、「代わりに」してみていいと思う

:あなたは、さらなる計算を行うことができますことを、

注意し、任意の例外が希望ここに私が使用しているものです失敗へのプロジェクト(ex)。 AFAIKこれは、一連の信頼できない操作を処理する慣習的な方法です。

+0

Opps、指摘してくれてありがとう、修正済み=) – Maverick

+1

私はスカラーの新人だから間違っているかもしれないが、これをコンパイルするには、a)import scala.util {{Success、Failure}}と単語「成功」と「失敗」の前に「大文字」を追加します。 –

関連する問題