我希望能够找到一个单词的第一个字母与组中的一个字母(例如" 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