为什么 scala.util.matching.Regex 'apparently' 在 Scala 提取器中失败?
Why scala.util.matching.Regex 'apparently' fails in Scala extractors?
我正在使用 Scala 提取器(即:模式数学中的正则表达式)来识别双精度和多精度,如下所示。
我的问题是:为什么 Regex 在模式匹配中使用时明显失败,而在 if/then/else 表达式链中使用时却清楚地提供预期结果?
val LONG = """^(0|-?[1-9][0-9]*)$"""
val DOUBLE = """NaN|^-?(0(\.[0-9]*)?|([1-9][0-9]*\.[0-9]*)|(\.[0-9]+))([Ee][+-]?[0-9]+)?$"""
val scalaLONG : scala.util.matching.Regex = LONG.r
val scalaDOUBLE : scala.util.matching.Regex = DOUBLE.r
val types1 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
text match {
case scalaLONG(long) => s"Long"
case scalaDOUBLE(double) => s"Double"
case _ => s"String"
})
// Results types1: Seq[String] = List("String", "Long", "String", "String", "String")
val types2 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
if(scalaDOUBLE.findFirstIn(text).isDefined) "Double" else
if(scalaLONG .findFirstIn(text).isDefined) "Long" else
"String")
// Results types2: Seq[String] = List("String", "Long", "Double", "Double", "Double")
正如您从上面看到的那样,types2
提供了预期的结果,而 types1
告诉 "String" 何时需要 "Double",显然指出了正则表达式处理。
编辑:在@alex-savitsky 和@leo-c 的帮助下,我得到了如下所示的结果,它按预期工作。但是,我必须 记住 在模式匹配中提供一个空参数列表,否则会给出错误的结果。这在我看来 容易出错。
val LONG = """^(?:0|-?[1-9][0-9]*)$"""
val DOUBLE = """^NaN|-?(?:0(?:\.[0-9]*)?|(?:[1-9][0-9]*\.[0-9]*)|(?:\.[0-9]+))(?:[Ee][+-]?[0-9]+)?$"""
val scalaLONG : scala.util.matching.Regex = LONG.r
val scalaDOUBLE : scala.util.matching.Regex = DOUBLE.r
val types1 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
text match {
case scalaLONG() => s"Long"
case scalaDOUBLE() => s"Double"
case _ => s"String"
})
// Results types1: Seq[String] = List("String", "Long", "Double", "Double", "Double")
val types2 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
if(scalaDOUBLE.findFirstIn(text).isDefined) "Double" else
if(scalaLONG .findFirstIn(text).isDefined) "Long" else
"String")
// Results types2: Seq[String] = List("String", "Long", "Double", "Double", "Double")
编辑:好的...尽管容易出错...这是一个提取器模式,它采用unapply
在幕后,在这种情况下,我们必须将参数传递给 unnapply
。 @alex-savitsky 在他的编辑中使用 _*
,这明确强制执行删除所有捕获组的意图。我觉得不错。
match
匹配整个输入,而 findFirstIn
可以匹配部分输入内容,有时会匹配更多。事实上,findFirstIn
会完全忽略你的边界标记 ^$
。
如果您打算匹配整个输入,请将 ^
放在正则表达式的开头,如 val DOUBLE = """^NaN|-?(0(\.[0-9]*)?|([1-9][0-9]*\.[0-9]*)|(\.[0-9]+))([Ee][+-]?[0-9]+)?$"""
,然后 types1
将正确匹配类型。
编辑:这是我针对你的问题的测试用例
object Test extends App {
val regex = """^NaN|-?(?:0(?:\.[0-9]*)?|(?:[1-9][0-9]*\.[0-9]*)|(?:\.[0-9]+))(?:[Ee][+-]?[0-9]+)?$""".r
println(Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map {
case regex() => "Double"
case _ => "String"
})
}
结果 List(String, String, Double, Double, Double)
如您所见,非捕获组使一切变得不同。
如果你还想使用捕获组,可以使用_*
忽略捕获结果:
object Test extends App {
val regex = """^NaN|-?(0(\.[0-9]*)?|([1-9][0-9]*\.[0-9]*)|(\.[0-9]+))([Ee][+-]?[0-9]+)?$""".r
println(Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map {
case regex(_*) => "Double"
case _ => "String"
})
}
由于您在 scalaDOUBLE 中定义了多个捕获组,因此您需要在相应的匹配案例中提供匹配数量的参数,如下所示:
val types1 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
text match {
case scalaLONG(long) => s"Long"
case scalaDOUBLE(d1, d2, d3, d4, d5) => s"Double"
case _ => s"String"
})
// types1: Seq[String] = List(String, Long, Double, Double, Double)
您可以查看抓取的分组,如下:
"-3.0E-05" match { case scalaDOUBLE(d1, d2, d3, d4, d5) => (d1, d2, d3, d4, d5) }
// res1: (String, String, String, String, String) = (3.0,null,3.0,null,E-05)
我正在使用 Scala 提取器(即:模式数学中的正则表达式)来识别双精度和多精度,如下所示。
我的问题是:为什么 Regex 在模式匹配中使用时明显失败,而在 if/then/else 表达式链中使用时却清楚地提供预期结果?
val LONG = """^(0|-?[1-9][0-9]*)$"""
val DOUBLE = """NaN|^-?(0(\.[0-9]*)?|([1-9][0-9]*\.[0-9]*)|(\.[0-9]+))([Ee][+-]?[0-9]+)?$"""
val scalaLONG : scala.util.matching.Regex = LONG.r
val scalaDOUBLE : scala.util.matching.Regex = DOUBLE.r
val types1 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
text match {
case scalaLONG(long) => s"Long"
case scalaDOUBLE(double) => s"Double"
case _ => s"String"
})
// Results types1: Seq[String] = List("String", "Long", "String", "String", "String")
val types2 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
if(scalaDOUBLE.findFirstIn(text).isDefined) "Double" else
if(scalaLONG .findFirstIn(text).isDefined) "Long" else
"String")
// Results types2: Seq[String] = List("String", "Long", "Double", "Double", "Double")
正如您从上面看到的那样,types2
提供了预期的结果,而 types1
告诉 "String" 何时需要 "Double",显然指出了正则表达式处理。
编辑:在@alex-savitsky 和@leo-c 的帮助下,我得到了如下所示的结果,它按预期工作。但是,我必须 记住 在模式匹配中提供一个空参数列表,否则会给出错误的结果。这在我看来 容易出错。
val LONG = """^(?:0|-?[1-9][0-9]*)$"""
val DOUBLE = """^NaN|-?(?:0(?:\.[0-9]*)?|(?:[1-9][0-9]*\.[0-9]*)|(?:\.[0-9]+))(?:[Ee][+-]?[0-9]+)?$"""
val scalaLONG : scala.util.matching.Regex = LONG.r
val scalaDOUBLE : scala.util.matching.Regex = DOUBLE.r
val types1 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
text match {
case scalaLONG() => s"Long"
case scalaDOUBLE() => s"Double"
case _ => s"String"
})
// Results types1: Seq[String] = List("String", "Long", "Double", "Double", "Double")
val types2 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
if(scalaDOUBLE.findFirstIn(text).isDefined) "Double" else
if(scalaLONG .findFirstIn(text).isDefined) "Long" else
"String")
// Results types2: Seq[String] = List("String", "Long", "Double", "Double", "Double")
编辑:好的...尽管容易出错...这是一个提取器模式,它采用unapply
在幕后,在这种情况下,我们必须将参数传递给 unnapply
。 @alex-savitsky 在他的编辑中使用 _*
,这明确强制执行删除所有捕获组的意图。我觉得不错。
match
匹配整个输入,而 findFirstIn
可以匹配部分输入内容,有时会匹配更多。事实上,findFirstIn
会完全忽略你的边界标记 ^$
。
如果您打算匹配整个输入,请将 ^
放在正则表达式的开头,如 val DOUBLE = """^NaN|-?(0(\.[0-9]*)?|([1-9][0-9]*\.[0-9]*)|(\.[0-9]+))([Ee][+-]?[0-9]+)?$"""
,然后 types1
将正确匹配类型。
编辑:这是我针对你的问题的测试用例
object Test extends App {
val regex = """^NaN|-?(?:0(?:\.[0-9]*)?|(?:[1-9][0-9]*\.[0-9]*)|(?:\.[0-9]+))(?:[Ee][+-]?[0-9]+)?$""".r
println(Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map {
case regex() => "Double"
case _ => "String"
})
}
结果 List(String, String, Double, Double, Double)
如您所见,非捕获组使一切变得不同。
如果你还想使用捕获组,可以使用_*
忽略捕获结果:
object Test extends App {
val regex = """^NaN|-?(0(\.[0-9]*)?|([1-9][0-9]*\.[0-9]*)|(\.[0-9]+))([Ee][+-]?[0-9]+)?$""".r
println(Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map {
case regex(_*) => "Double"
case _ => "String"
})
}
由于您在 scalaDOUBLE 中定义了多个捕获组,因此您需要在相应的匹配案例中提供匹配数量的参数,如下所示:
val types1 = Seq("abc", "3", "3.0", "-3.0E-05", "NaN").map(text =>
text match {
case scalaLONG(long) => s"Long"
case scalaDOUBLE(d1, d2, d3, d4, d5) => s"Double"
case _ => s"String"
})
// types1: Seq[String] = List(String, Long, Double, Double, Double)
您可以查看抓取的分组,如下:
"-3.0E-05" match { case scalaDOUBLE(d1, d2, d3, d4, d5) => (d1, d2, d3, d4, d5) }
// res1: (String, String, String, String, String) = (3.0,null,3.0,null,E-05)