如何在Scala中使用正则表达式进行模式匹配?

Bru*_*son 118 regex scala pattern-matching

我希望能够找到一个单词的第一个字母和一个组中的一个字母(如"ABC")之间的匹配.在伪代码中,这可能看起来像:

case Process(word) =>
   word.firstLetter match {
      case([a-c][A-C]) =>
      case _ =>
   }
}
Run Code Online (Sandbox Code Playgroud)

但是我如何抓住Scala中的第一个字母而不是Java呢?如何正确表达正则表达式?是否可以在案例类中执行此操作?

asm*_*asm 229

您可以这样做,因为正则表达式定义了提取器,但您需要首先定义正则表达式模式.我没有访问Scala REPL来测试这个,但是这样的东西应该可行.

val Pattern = "([a-cA-C])".r
word.firstLetter match {
   case Pattern(c) => c bound to capture group here
   case _ =>
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意你*必须*在正则表达式中使用组:```val Pattern ="[a-cA-C]".r```将不起作用.这是因为match-case使用```unapplySeq(target:Any):Option [List [String]]```,它返回匹配的组. (32认同)
  • @rakensi No.`val r ="[A-Ca-c]".r; 'a'匹配{case r()=>}`.http://www.scala-lang.org/api/current/#scala.util.matching.Regex (10认同)
  • 请注意,您不能声明捕获组,然后不使用它(例如,案例Pattern()将不匹配) (4认同)
  • @JeremyLeipzig忽略群体:`val r ="([A-Ca-c])".r; "C"匹配{case r(_*)=>}`. (3认同)
  • 这是[StringLike](http://www.scala-lang.org/api/current/#scala.collection.immutable.StringLike)上的一个方法,它返回一个[Regex](http://www.scala-lang.组织/ API /电流/#scala.util.matching.Regex). (2认同)

kir*_*uku 116

从版本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
Run Code Online (Sandbox Code Playgroud)

更好的是可以绑定正则表达式组:

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
Run Code Online (Sandbox Code Playgroud)

也可以设置更详细的绑定机制:

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
Run Code Online (Sandbox Code Playgroud)

关于可能性的一个令人印象深刻的例子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")
  }
}
Run Code Online (Sandbox Code Playgroud)


sep*_*p2k 48

正如delnan所指出的,matchScala中的关键字与正则表达式无关.要确定字符串是否与正则表达式匹配,可以使用该String.matches方法.要查明字符串是以a,b还是c开头是大写还是大写,正则表达式将如下所示:

word.matches("[a-cA-C].*")
Run Code Online (Sandbox Code Playgroud)

您可以将此正则表达式理解为"其中一个字符a,b,c,A,B或C后跟任何内容"(.表示"任何字符",*表示"零次或多次",因此".*"是任何字符串) .


Fab*_*eeg 24

为了扩展安德鲁的答案:正则表达式定义提取器的事实可以用于使用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.
}
Run Code Online (Sandbox Code Playgroud)


Jan*_*anx 8

String.matches是在正则表达式中进行模式匹配的方法.

但是作为一个方便的说法,真正的Scala代码中的word.firstLetter看起来像:

word(0)
Run Code Online (Sandbox Code Playgroud)

Scala将字符串视为Char的序列,因此如果由于某种原因你想显式获取String的第一个字符并匹配它,你可以使用这样的东西:

"Cat"(0).toString.matches("[a-cA-C]")
res10: Boolean = true
Run Code Online (Sandbox Code Playgroud)

我并不是说这是进行正则表达式模式匹配的一般方法,但它符合您提出的首先找到String的第一个字符然后将其与正则表达式匹配的方法.

编辑:要明确,我这样做的方式是,正如其他人所说:

"Cat".matches("^[a-cA-C].*")
res14: Boolean = true
Run Code Online (Sandbox Code Playgroud)

只是想展示一个尽可能接近你的初始伪代码的例子.干杯!

  • ``"Cat"(0).toString``可以更清楚地写成``"Cat"取1``,imho. (3认同)

Mik*_*yte 8

请注意,来自@AndrewMyers的答案的方法将整个字符串与正则表达式匹配,其效果是使用^和将字符串两端的正则表达式锚定$.例:

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
Run Code Online (Sandbox Code Playgroud)

并且.*最后没有:

scala> val MY_RE2 = "(foo|bar)".r
MY_RE2: scala.util.matching.Regex = (foo|bar)

scala> val result = "foo123" match { case MY_RE2(m) => m; case _ => "No match" }
result: String = No match
Run Code Online (Sandbox Code Playgroud)

  • 惯用语是, `val MY_RE2 = "(foo|bar)".r.unanchored ;“foo123”匹配 { case MY_RE2(_*) =&gt; }`。更惯用的是,“val re”不全部大写。 (2认同)

Hai*_*mei 7

首先,我们应该知道正则表达式可以单独使用。这是一个例子:

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
Run Code Online (Sandbox Code Playgroud)

其次,我们应该注意到,将正则表达式与模式匹配相结合将非常强大。这是一个简单的例子。

val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
"2014-11-20" match {
  case date(year, month, day) => "hello"
} // output: hello
Run Code Online (Sandbox Code Playgroud)

实际上,正则表达式本身已经非常强大。我们唯一要做的就是通过Scala使它更强大。以下是Scala文档中的更多示例:http : //www.scala-lang.org/files/archive/api/current/index.html#scala.util.matching.Regex