如何在 Scala 中使用正则表达式匹配
How to use match with regular expressions in Scala
我开始学习 Scala 并想使用正则表达式来匹配字符串中的字符,这样我就可以填充字符及其值(字符串值、数字等)的可变映射,然后打印结果。
我查看了关于 SO 的几个答案并浏览了 Scala 文档,但似乎无法正确理解。我有一个简短的 Lexer class,目前看起来像这样:
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 中使用正则表达式的正确方法.我想我想要这段代码做什么很清楚,我真的很感激能帮助理解这一点。如果需要更多信息,我会尽我所能
这个官方文档有很多例子: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
class 也有 unapplySeq
方法来支持模式匹配。这使它成为 extractor object。可以直接使用(不常用):
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
上输入 return。文档解释得很好:
The return type of an unapply should be chosen as follows:
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)].
Sometimes, the number of values to extract isn’t fixed and we would
like to return an arbitrary number of values, depending on the input.
For this use case, you can define extractors with an unapplySeq method
which returns an Option[Seq[T]]. Common examples of these patterns
include deconstructing a List using case List(x, y, z) => and
decomposing a String using a regular expression Regex, such as case
r(name, remainingFields @ _*) =>
简而言之,您的正则表达式可能匹配一个或多个组,因此您需要 return 一个 list/seq。它必须包含在 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
我开始学习 Scala 并想使用正则表达式来匹配字符串中的字符,这样我就可以填充字符及其值(字符串值、数字等)的可变映射,然后打印结果。
我查看了关于 SO 的几个答案并浏览了 Scala 文档,但似乎无法正确理解。我有一个简短的 Lexer class,目前看起来像这样:
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 中使用正则表达式的正确方法.我想我想要这段代码做什么很清楚,我真的很感激能帮助理解这一点。如果需要更多信息,我会尽我所能
这个官方文档有很多例子: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
class 也有 unapplySeq
方法来支持模式匹配。这使它成为 extractor object。可以直接使用(不常用):
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
上输入 return。文档解释得很好:
The return type of an unapply should be chosen as follows:
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)].
Sometimes, the number of values to extract isn’t fixed and we would like to return an arbitrary number of values, depending on the input. For this use case, you can define extractors with an unapplySeq method which returns an Option[Seq[T]]. Common examples of these patterns include deconstructing a List using case List(x, y, z) => and decomposing a String using a regular expression Regex, such as case r(name, remainingFields @ _*) =>
简而言之,您的正则表达式可能匹配一个或多个组,因此您需要 return 一个 list/seq。它必须包含在 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