如何在 Scala 中使用正则表达式匹配

Pum*_*ath 2 regex scala matching

我开始学习 Scala 并想使用正则表达式来匹配字符串中的字符,以便我可以填充字符及其值(字符串值、数字等)的可变映射,然后打印结果。

我已经查看了关于 SO 的几个答案并浏览了 Scala Docs,但似乎无法正确理解。我有一个简短的 Lexer 类,目前看起来像这样:

class Lexer {

    private val tokens: mutable.Map[String, Any] = collection.mutable.Map()

    private def checkCharacter(char: Character): Unit = {
        val Operator = "[-+*/^%=()]".r
        val Digit = "[\\d]".r
        val Other = "[^\\d][^-+*/^%=()]".r
        char.toString match {
            case Operator(c) => tokens(c) = "Operator"
            case Digit(c) => tokens(c) = Integer.parseInt(c)
            case Other(c) => tokens(c) = "Other" // Temp value, write function for this
        }
    }

    def lex(input: String): Unit = {
        val inputArray = input.toArray
        for (s <- inputArray)
            checkCharacter(s)
        for((key, value) <- tokens)
            println(key + ": " + value)
    }
}
Run Code Online (Sandbox Code Playgroud)

我对那种奇怪的方法语法 Operator(c) 感到非常困惑,我已经看到它被用来处理要匹配的值,并且我也不确定这是否是在 Scala 中使用正则表达式的正确方法。我想我想要这段代码做的很清楚,我真的很感激理解这一点的一些帮助。如果需要更多信息,我会提供我能提供的

yǝs*_*ǝla 5

这个官方文档有很多例子:https : //www.scala-lang.org/api/2.12.1/scala/util/matching/Regex.html。可能令人困惑的是正则表达式的类型及其在模式匹配中的用途......

您可以使用.r以下命令从任何字符串构造正则表达式:

scala> val regex = "(something)".r
regex: scala.util.matching.Regex = (something)
Run Code Online (Sandbox Code Playgroud)

regex将成为一个对象,它具有一些有用的方法可以找到匹配的组,例如findAllIn.

在 Scala 中,使用模式匹配来安全提取值是惯用的,因此Regex类也有unapplySeq支持模式匹配的方法。这使它成为提取器对象。您可以直接使用它(不常见):

scala> regex.unapplySeq("something")
res1: Option[List[String]] = Some(List(something))
Run Code Online (Sandbox Code Playgroud)

或者您可以让 Scala 编译器在您进行模式匹配时为您调用它:

scala> "something" match {
     |    case regex(x) => x
     |    case _ => ???
     | }
res2: String = something
Run Code Online (Sandbox Code Playgroud)

你可能会问为什么这个返回类型在unapply/unapplySeq. 该文档很好地解释了它:

unapply 的返回类型应选择如下:

If it is just a test, return a Boolean. For instance case even().
If it returns a single sub-value of type T, return an Option[T].
If you want to return several sub-values T1,...,Tn, group them in an optional tuple Option[(T1,...,Tn)].
Run Code Online (Sandbox Code Playgroud)

有时,要提取的值的数量不是固定的,我们希望根据输入返回任意数量的值。对于此用例,您可以使用返回 Option[Seq[T]] 的 unapplySeq 方法定义提取器。这些模式的常见示例包括使用 case List(x, y, z) => 解构 List 和使用正则表达式 Regex 分解 String,例如 case r(name, remainingFields @ _*) =>

简而言之,您的正则表达式可能匹配一个或多个组,因此您需要返回一个列表/序列。它必须被包裹在一个Option符合提取器合同的条件下。

您使用正则表达式的方式是正确的,我只是将您的函数映射到输入数组上以避免创建可变映射。也许是这样的:

class Lexer {

    private def getCharacterType(char: Character): Any = {
        val Operator = "([-+*/^%=()])".r
        val Digit = "([\\d])".r
        //val Other = "[^\\d][^-+*/^%=()]".r
        char.toString match {
            case Operator(c) => "Operator"
            case Digit(c) => Integer.parseInt(c)
            case _ => "Other" // Temp value, write function for this
        }
    }

    def lex(input: String): Unit = {
        val inputArray = input.toArray
        val tokens = inputArray.map(x => x -> getCharacterType(x))
        for((key, value) <- tokens)
            println(key + ": " + value)
    }
}

scala> val l = new Lexer()
l: Lexer = Lexer@60f662bd

scala> l.lex("a-1")
a: Other
-: Operator
1: 1
Run Code Online (Sandbox Code Playgroud)