scala 模式匹配支持正则吗_关于正则表达式:如何在Scala中使用正则表达式进行模式匹配?...

我希望能够找到一个单词的第一个字母与组中的一个字母(例如" ABC")之间的匹配。 在伪代码中,这可能类似于:

case Process(word) =>

word.firstLetter match {

case([a-c][A-C]) =>

case _ =>

}

}

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

请注意:在Scala(和* ML语言)中,模式匹配还有另一个与正则表达式完全不同的含义。

您可能需要[a-cA-C]作为该正则表达式。

在scala 2.8中,字符串将转换为Traversable(如List和Array),如果要使用前三个字符,请尝试将"my string".take(3)用于第一个"foo".head

您可以执行此操作,因为正则表达式定义了提取器,但是您需要首先定义正则表达式模式。我没有使用Scala REPL进行测试的方法,但是类似的方法应该可以工作。

val Pattern ="([a-cA-C])".r

word.firstLetter match {

case Pattern(c) => c bound to capture group here

case _ =>

}

请注意,您无法声明捕获组然后再不使用它(即case Pattern()在此处不匹配)

注意,必须在正则表达式中使用组:val Pattern ="[a-cA-C]".r将不起作用。这是因为区分大小写使用unapplySeq(target: Any): Option[List[String]],它返回匹配的组。

.r在val Pattern = ...末尾是什么意思?

它是StringLike上的一个返回正则表达式的方法。

@rakensi号val r ="[A-Ca-c]".r ; a match { case r() => }。 scala-lang.org/api/current/#scala.util.matching.Regex

@JeremyLeipzig忽略组:val r ="([A-Ca-c])".r ;"C" match { case r(_*) => }。

从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

在博客文章《动态类型简介》中展示了一个令人印象深刻的示例,说明了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")

}

}

非常喜欢这个答案,但是当尝试在REPL之外使用它时,它被锁定了(即,与REPL相同的代码在运行的应用程序中不起作用)。将$符号用作行结束模式也存在问题:编译器抱怨缺少字符串终止。

@Rajish:不知道可能是什么问题。从2.10开始,我回答的所有内容都是有效的Scala代码。

@sschaef:那个case p.firstName.lastName.Map(...模式-我到底是怎么读的?

@ErikAllik将其读为类似"当firstName以Jo开头并且secondName与给定的正则表达式匹配时,匹配成功。"这更多是Scalas功能的示例,我不会在生产代码中以这种方式编写此用例。顺便说一句,应该用列表代替Map的用法,因为Map是无序的,并且对于更多的值,它不再保证正确的变量与正确的匹配器匹配。

@sschaef:我认为这种魔术已经走得太远了……除非您在应用程序中进行了一些繁琐的正则表达式模式匹配(即使那样,您仍需要某种更易理解的方式)。

另外,请注意,使用内部捕获组会弄乱组绑定。可以修改代码来修复该错误,但是我对Scala的了解还不够。

我也不会使用它,但是这个动态示例很有趣。

这对于快速原型制作非常方便,但是请注意,每次检查匹配项时,都会创建一个Regex的新实例。这是相当昂贵的操作,涉及到正则表达式模式的编译。

与Rubys casewhen语句类似。

看来,如果您使用组,则必须附加${variable}。

如果正则表达式包含引号文字:case r"stuff " more stuff (.*)$s" => s,这似乎也无法编译。您必须使用三引号代替:case r"""stuff" more stuff (.*)$s"""。

希望一些更简单的方法是标准库字符串内插的一部分。您是否已向开发人员提出此建议?

似乎已请求类似的内容:issue.scala-lang.org/browse/SI-7496

正如delnan指出的那样,Scala中的match关键字与正则表达式无关。要查找字符串是否与正则表达式匹配,可以使用String.matches方法。为了确定字符串是以小写还是大写的a,b或c开头,正则表达式如下所示:

word.matches("[a-cA-C].*")

您可以将此正则表达式读为"字符a,b,c,A,B或C之一,后跟任何字符"(.表示"任何字符",*表示"零次或多次",所以"。 *"是任何字符串)。

为了进一步说明安德鲁的答案:正则表达式定义提取器的事实可以很好地使用Scala的模式匹配来很好地分解由正则表达式匹配的子字符串,例如:

val Process ="""([a-cA-C])([^\s]+)""".r // define first, rest is non-space

for (p

case Process("b", _) => println("first: 'a', some rest")

case Process(_, rest) => println("some first, rest:" + rest)

// etc.

}

我真的对高帽^感到困惑。我虽然" ^"的意思是"匹配行的开头"。它与该行的开头不匹配。

@MichaelLafayette:在字符类([])内,插入符号表示取反,因此[^\s]表示非空格。

请注意,@ 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

并且最后没有.*:

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

习惯上是val MY_RE2 ="(foo|bar)".r.unanchored ;"foo123" match { case MY_RE2(_*) => }。 更习惯地说,val re没有大写字母。

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

但是,方便起见,实际Scala代码中的word.firstLetter看起来像:

word(0)

Scala将字符串视为Char的序列,因此,如果出于某种原因您想要显式获取String的第一个字符并进行匹配,则可以使用如下代码:

"Cat"(0).toString.matches("[a-cA-C]")

res10: Boolean = true

我并不是提议将其作为进行正则表达式模式匹配的一般方法,但是它与您建议的方法相一致,即首先找到String的第一个字符,然后将其与正则表达式匹配。

编辑:

明确地说,我这样做的方式是,正如其他人所说的那样:

"Cat".matches("^[a-cA-C].*")

res14: Boolean = true

只是想显示一个尽可能接近初始伪代码的示例。干杯!

"Cat"(0).toString可以更清楚地写为"Cat" take 1,恕我直言。

另外(尽管这是一个古老的讨论-我可能是在挖洞):您可以从最后删除。*,因为它不会为正则表达式添加任何值。只是" Cat" .matches(" ^ [a-cA-C]")

今天在2.11,val r ="[A-Ca-c]".r ;"cat"(0) match { case r() => }。

嗨帽子(^)是什么意思?

它是该行的起点(cs.duke.edu/csl/docs/unix_course/intro-73.html)。因此,如果它是行中的第一件事,那么踩hi之后的所有内容都将匹配该模式。

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值