Как использовать соответствие с регулярными выражениями в Scala - PullRequest
0 голосов
/ 07 ноября 2019

Я начинаю изучать 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)
    }
}

Я довольно озадачен странным синтаксисом метода Operator (c), который, как я видел, используется для обработки значения ви я также не уверен, что это правильный способ использования регулярных выражений в Scala. Я думаю, что я хочу, чтобы этот код был понятным, я действительно был бы признателен за помощь в понимании этого. Если потребуется дополнительная информация, я предоставлю все, что смогу

1 Ответ

3 голосов
/ 07 ноября 2019

В этом официальном документе много примеров: 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)

Вашregex становится объектом, который имеет несколько полезных методов для поиска подходящих групп, таких как findAllIn.

В Scala идиоматично использовать сопоставление с образцом для безопасного извлечения значений, таким образом, класс Regex такжеимеет unapplySeq метод для поддержки сопоставления с образцом. Это делает его объектом-экстрактором . Вы можете использовать его напрямую (не часто):

scala> regex.unapplySeq("something")
res1: Option[List[String]] = Some(List(something))

или позволить компилятору Scala вызывать его для вас при сопоставлении с образцом:

scala> "something" match {
     |    case regex(x) => x
     |    case _ => ???
     | }
res2: String = something

Вы можете спросить, почему именно этотип возврата на unapply/unapplySeq. Документ объясняет это очень хорошо:

Тип возвращаемого значения неприменяемого следует выбирать следующим образом:

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)].

Иногда количество извлекаемых значений не является фиксированным имы хотели бы вернуть произвольное количество значений, в зависимости от ввода. Для этого варианта использования вы можете определить экстракторы с помощью метода unapplySeq, который возвращает Option [Seq [T]]. Типичные примеры этих шаблонов включают деконструкцию List с использованием case List (x, y, z) => и декомпозицию String с использованием регулярного выражения Regex, такого как case r (name, ОстальноеFields @ _ *) =>

Короче говоря, ваше регулярное выражение может соответствовать одной или нескольким группам, поэтому вам нужно вернуть список / секв. Это должно быть заключено в 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
...