如何检查一个字符串是否与Scala中的正则表达式完全匹配?


80

假设我有一个正则表达式模式,我想匹配许多字符串。

val Digit = """\d""".r

我只想检查给定的String是否完全匹配Regex。在Scala中,有什么好的和惯用的方法来做到这一点?

我知道我可以在Regexes上进行模式匹配,但是这种情况在语法上并不令人满意,因为我没有要提取的组:

scala> "5" match { case Digit() => true case _ => false }
res4: Boolean = true

或者,我可以回到基本的Java模式:

scala> Digit.pattern.matcher("5").matches
res6: Boolean = true

这也不优雅。

有更好的解决方案吗?


我认为"5" match { case Digit() => true case _ => false }看起来比使用基础模式对象更好。
Mygod '17年

Answers:


66

回答我自己的问题,我将使用“ pimp my library pattern”

object RegexUtils {
  implicit class RichRegex(val underlying: Regex) extends AnyVal {
    def matches(s: String) = underlying.pattern.matcher(s).matches
  }
}

像这样使用

import RegexUtils._
val Digit = """\d""".r
if (Digit matches "5") println("match")
else println("no match")

除非有人提出更好的(标准)解决方案。

笔记

  • 我没有拉皮条String来限制潜在副作用的范围。

  • unapplySeq 在这种情况下,阅读效果不佳。


您是否有任何特定的副作用?我String改为拉皮条纸,尽管具有String成员函数 ,但到目前为止效果很好matches(regex: String)
KajMagnus 2012年

1
我也使用了一个函数misses。匹配和不匹配:-)不得不写!s.matches(r)而不是s misses r。嗯
KajMagnus

1
"5" matches "\\d"@polygenelubricants建议的内置函数如何?
埃里克·卡普伦2014年

2
数据与模式匹配,反之亦然。正则表达式上的scaladoc对缺少用于“ matches”的布尔值做出了很大的贡献。就个人而言,我认为您已经将一个不错的选择换成了一个笨拙的if-else。如果您不关心群组,请使用case r(_*) =>
som-snytt

必须有一种方法,而无需导入外部库...
Jameela Huq

56

我不太了解Scala,但是看来您可以做到:

"5".matches("\\d")

参考文献


25
是的,这很有效,但缺点是每次尝试匹配时都会编译模式。由于性能原因,我想避免这种情况。
mkneissl 2010年

3
@mkneissl:看来您.pattern.matcher(text).matches是要走的路。您可以在某些实用程序方法或重载的运算符下(如果Scala支持它)将详细程度隐藏起来。
polygenelubricants 2010年

4
谢谢,这就是我要做的,请参阅我的回答。我希望回答自己的问题是Stack Overflow上的可接受行为... Meta说是...
mkneissl 2010年

2
@ed。那甚至更慢更脆弱,那为什么呢?
埃里克·卡普伦2014年

作为参考的链接已断开
Valy Dia

13

对于完全匹配,您可以使用unapplySeq。此方法尝试匹配目标(完全匹配)并返回匹配项。

scala> val Digit = """\d""".r
Digit: scala.util.matching.Regex = \d

scala> Digit unapplySeq "1"
res9: Option[List[String]] = Some(List())

scala> Digit unapplySeq "123"
res10: Option[List[String]] = None

scala> Digit unapplySeq "string"
res11: Option[List[String]] = None

4
为true时,unapply和unapplySeq的主要用法隐含在块的cases中match
Randall Schulz 2010年

11
  """\d""".r.unapplySeq("5").isDefined            //> res1: Boolean = true
  """\d""".r.unapplySeq("a").isDefined            //> res2: Boolean = false

嗯 为什么两年后发布stackoverflow.com/a/3022478/158823的副本?
mkneissl

2
您最初的问题要求结果以“ true”或“ false”结尾,而不是“ Some”或“ None”。据我所知,isDefined在2年前不是库的一部分,但也许是。无论如何,我的回答不是重复的;-)
杰克

我知道,这不是重复的。抱歉。
mkneissl

1
没有问题;-)我的错误,我应该在回答中解释为什么使用isDefined。仅给出代码作为答案通常是一个坏主意,所以这对我来说是不好的。
2013年

1

答案在正则表达式中:

val Digit = """^\d$""".r

然后使用现有方法之一。


3
我认为锚点不是这里的问题。String/Pattern/Matcher.matches,至少在Java中,已经是整个字符串匹配了。我认为问题只是Scala中正则表达式的样式/惯用语,即“现有方法之一”是什么。
polygenelubricants 2010年

@polygenelubricants好吧,Matcher.matches是一种畸变。好的,尽管我不知道Java库是否真正利用了它,但它使某些优化成为可能。但是正则表达式表示需要完全匹配的标准方法是使用锚点。由于Scala库没有提供完全匹配的方法,因此正确的方法是使用定位符。要么使用Java库,要么使用Java库。
Daniel C. Sobral

锚固不是问题。另请参见Vasil答案中的“ 123”示例。
mkneissl

5
@Daniel您可能会漏掉这一点-我的问题是,如果我只需要知道正则表达式是否完全匹配,那么在Scala中表达它的一种好方法是什么?有很多可行的解决方案,但是总的来说,我认为Regex中缺少一种方法可以做到这一点,而别无其他。要回答您的评论中的问题:unapplySeq与findFirstMatch的区别在于,我必须更改Regex以添加锚点。这两种方法都不会立即表达我的意图,也不会返回布尔值,也就是说,我必须从Option变为Boolean(没问题,但是会增加混乱)。
mkneissl

1
@mkneissl我不喜欢Java的概念matches,但是可以。至于Optionvs Boolean,添加nonEmpty到最后,你会得到Boolean
Daniel C. Sobral

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.