我希望能够找到一个单词的第一个字母和一个组中的一个字母(如“ABC”)之间的匹配。在伪代码中,这可能类似于:
case Process(word) =>
word.firstLetter match {
case([a-c][A-C]) =>
case _ =>
}
}
但是我如何抓住Scala中的第一个字母而不是Java?如何正确表达正则表达式?是否可以在case class内完成此操作?
答案 0 :(得分:225)
您可以这样做,因为正则表达式定义了提取器,但您需要首先定义正则表达式模式。我没有访问Scala REPL来测试这个,但是这样的事情应该可行。
val Pattern = "([a-cA-C])".r
word.firstLetter match {
case Pattern(c) => c bound to capture group here
case _ =>
}
答案 1 :(得分:115)
从版本2.10开始,可以使用Scala的字符串插值功能:
implicit class Regex(sc: StringContext) {
def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*)
}
scala> "123" match { case r"\d+" => true case _ => false }
res34: Boolean = true
更好的是可以绑定正则表达式组:
scala> "123" match { case r"(\d+)$d" => d.toInt case _ => 0 }
res36: Int = 123
scala> "10+15" match { case r"(\d\d)${first}\+(\d\d)${second}" => first.toInt+second.toInt case _ => 0 }
res38: Int = 25
还可以设置更详细的绑定机制:
scala> object Doubler { def unapply(s: String) = Some(s.toInt*2) }
defined module Doubler
scala> "10" match { case r"(\d\d)${Doubler(d)}" => d case _ => 0 }
res40: Int = 20
scala> object isPositive { def unapply(s: String) = s.toInt >= 0 }
defined module isPositive
scala> "10" match { case r"(\d\d)${d @ isPositive()}" => d.toInt case _ => 0 }
res56: Int = 10
博客文章 Introduction to Type Dynamic 中显示了关于Dynamic
可行内容的一个令人印象深刻的示例:
object T {
class RegexpExtractor(params: List[String]) {
def unapplySeq(str: String) =
params.headOption flatMap (_.r unapplySeq str)
}
class StartsWithExtractor(params: List[String]) {
def unapply(str: String) =
params.headOption filter (str startsWith _) map (_ => str)
}
class MapExtractor(keys: List[String]) {
def unapplySeq[T](map: Map[String, T]) =
Some(keys.map(map get _))
}
import scala.language.dynamics
class ExtractorParams(params: List[String]) extends Dynamic {
val Map = new MapExtractor(params)
val StartsWith = new StartsWithExtractor(params)
val Regexp = new RegexpExtractor(params)
def selectDynamic(name: String) =
new ExtractorParams(params :+ name)
}
object p extends ExtractorParams(Nil)
Map("firstName" -> "John", "lastName" -> "Doe") match {
case p.firstName.lastName.Map(
Some(p.Jo.StartsWith(fn)),
Some(p.`.*(\\w)$`.Regexp(lastChar))) =>
println(s"Match! $fn ...$lastChar")
case _ => println("nope")
}
}
答案 2 :(得分:46)
正如delnan所指出的,Scala中的match
关键字与正则表达式无关。要确定字符串是否与正则表达式匹配,可以使用String.matches
方法。要查明字符串是以a,b还是c开头的大写字母,正则表达式如下所示:
word.matches("[a-cA-C].*")
您可以将此正则表达式理解为“其中一个字符a,b,c,A,B或C后跟任何字符”(.
表示“任何字符”,*
表示“零或更多次“,所以”。*“是任何字符串。”
答案 3 :(得分:24)
在Andrew's answer上展开一点:正则表达式定义提取器的事实可以用于使用Scala的模式匹配很好地分解正则表达式匹配的子串,例如:
val Process = """([a-cA-C])([^\s]+)""".r // define first, rest is non-space
for (p <- Process findAllIn "aha bah Cah dah") p match {
case Process("b", _) => println("first: 'a', some rest")
case Process(_, rest) => println("some first, rest: " + rest)
// etc.
}
答案 4 :(得分:8)
请注意,@ AndrewMyers的答案中的方法将整个字符串与正则表达式匹配,并使用^
和{{将字符串两端的正则表达式锚定在一起1}}。例如:
$
最后没有scala> val MY_RE = "(foo|bar).*".r
MY_RE: scala.util.matching.Regex = (foo|bar).*
scala> val result = "foo123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = foo
scala> val result = "baz123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = No match
scala> val result = "abcfoo123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = No match
:
.*
答案 5 :(得分:7)
String.matches是在正则表达式中进行模式匹配的方法。
但是,除了方便之外,真正的Scala代码中的word.firstLetter看起来像:
word(0)
Scala将字符串视为Char的序列,因此如果由于某种原因你想明确获取字符串的第一个字符并匹配它,你可以使用类似的东西:
"Cat"(0).toString.matches("[a-cA-C]")
res10: Boolean = true
我并不是说这是进行正则表达式模式匹配的一般方法,但它符合您提出的方法,首先找到String的第一个字符,然后将其与正则表达式匹配。
编辑: 要明确的是,我这样做的方式就像其他人所说的那样:
"Cat".matches("^[a-cA-C].*")
res14: Boolean = true
只想展示一个尽可能接近您的初始伪代码的示例。干杯!
答案 6 :(得分:4)
首先我们应该知道可以单独使用正则表达式。这是一个例子:
import scala.util.matching.Regex
val pattern = "Scala".r // <=> val pattern = new Regex("Scala")
val str = "Scala is very cool"
val result = pattern findFirstIn str
result match {
case Some(v) => println(v)
case _ =>
} // output: Scala
其次,我们应该注意到将正则表达式与模式匹配相结合将非常强大。这是一个简单的例子。
val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
"2014-11-20" match {
case date(year, month, day) => "hello"
} // output: hello
事实上,正则表达本身已经非常强大;我们唯一需要做的就是让Scala更强大。以下是Scala文档中的更多示例:http://www.scala-lang.org/files/archive/api/current/index.html#scala.util.matching.Regex