java - 为什么 scala.util.matching.Regex 'apparently' 在 Scala 提取器中失败?

标签 java regex scala pattern-matching data-extraction

我正在使用 Scala 提取器(即:模式数学中的正则表达式)来识别 double 和长整型数,如下所示。

我的问题是:为什么正则表达式在模式匹配中使用时明显失败,而在 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"
    })
}

关于java - 为什么 scala.util.matching.Regex 'apparently' 在 Scala 提取器中失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48304488/

相关文章:

regex - 捕获组引用 + 数字

javascript - 仅当字符串包含 RegExp 中指定的所有字符时才匹配

java - 在滑动窗口上重复有效地计算线性回归模型

java - 我们可以在一个接口(interface)中有一个 main() 并在实现这个接口(interface)的类中有不同的 main() 实现吗?

java - 使用 Jackson 反序列化包含不同类型的 JSON 数组

jquery - 如何同时替换字符和数字?

scala - scala-redis 连接器中的隐含值不明确

scala - 从 Scala 中的类型检查中删除路径依赖

scala - Scala 中类型安全的完美二叉树

java - 弹跳后 body 获得额外动力