文字列がScalaの正規表現と完全に一致するかどうかを確認するにはどうすればよいですか?


80

多くの文字列を一致させたい正規表現パターンがあると仮定します。

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

特定の文字列が正規表現と完全に一致するかどうかを確認したいだけです。Scalaでこれを行うための良い慣用的な方法は何ですか?

正規表現でパターンマッチできることは知っていますが、抽出するグループがないため、この場合、構文的にはあまり満足のいくものではありません。

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 2017年

回答:


66

自分の質問に答える「ライブラリパターンをポン引きする」を使用します

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 2012

1
"5" matches "\\d"@polygenelubricantsが提案したビルトインはどうですか?
Erik Kaplun 2014

2
データはパターンに一致しますが、その逆はありません。正規表現のscaladocは、「一致」のブール値がないことについて大きな問題を抱えています。個人的には、あなたは素敵な試合をもっと不格好なif-elseと交換したと思います。グループを気にしない場合は、を使用してくださいcase r(_*) =>
som-snytt 2014年

...外部ライブラリをインポートせずにこれを行う方法がなければならない
Jameela Huq

56

Scalaについてはよくわかりませんが、次のことができるようです。

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

参考文献


25
まあ、それは機能しますが、パターンが一致しようとするたびにコンパイルされるという欠点があります。パフォーマンス上の理由から、これは避けたいと思います。
mkneissl 2010年

3
@mkneissl:それならあなた.pattern.matcher(text).matchesが行く道のようです。Scalaがサポートしている場合は、ユーティリティメソッドやオーバーロードされた演算子などで詳細度を非表示にできます。
多遺伝子潤滑剤2010年

4
おかげで、それは私がやろうとしていることです、私の答えを見てください。私はメタはそれは...と言う...スタックオーバーフロー上の行動を受け入れている自分の質問に答える願って
mkneissl

2
@ed。それはさらに遅くて無愛想です、それでなぜですか?
Erik Kaplun 2014

参照として与えられたリンクが壊れています
ValyDia19年

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の主な用途は、暗黙的にブロックcaseのsにありmatchます。
Randall Schulz

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

うーん。2年後にstackoverflow.com/a/3022478/158823の複製を投稿するのはなぜですか?
mkneissl 2013年

2
元の質問では、「一部」または「なし」ではなく、「真」または「偽」で終わる結果が求められました。私の知る限り、isDefinedは2年前にはライブラリの一部ではありませんでしたが、おそらくそうでした。とにかく、私の答えは重複ではありません;-)
ジャック

なるほど、それは重複ではありません。ごめんなさい。
mkneissl 2013年

1
問題はありません;-)私の間違い、私が答えでisDefinedを使用している理由を説明する必要がありました。答えとしてコードを与えることは一般的に悪い考えなので、それは私の悪いことです。
ジャック

1

答えは正規表現にあります:

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

次に、既存の方法の1つを使用します。


3
ここではアンカーが問題になるとは思いません。String/Pattern/Matcher.matches、少なくともJavaでは、文字列全体がすでに一致しています。問題は、Scalaでの正規表現のスタイル/イディオム、つまり「既存の方法の1つ」とは何かだと思います。
多遺伝子潤滑剤2010年

@polygenelubricantsまあ、Matcher.matches異常です。わかりました。Javaライブラリが実際にそれを利用しているかどうかはわかりませんが、いくつかの最適化が可能になります。ただし、正規表現で完全一致が必要であることを表す標準的な方法は、アンカーを使用することです。Scalaライブラリは完全一致メソッドを提供していないため、それを行う適切な方法はアンカーを使用することです。それか、Javaライブラリを使用してください。
ダニエルC.ソブラル2010年

固定は問題ではありません。Vasilの回答の「123」の例も参照してください。
mkneissl 2010年

5
@Daniel要点を見逃しているかもしれません-私の質問は、正規表現が完全に一致するかどうかだけを知る必要がある場合、Scalaでそれを表現する良い方法は何ですか?実用的な解決策はたくさんありますが、要約すると、それを実行するだけで他には何も実行しない方法が正規表現に欠けていると思います。コメントの質問に答えるには:unapplySeqとfindFirstMatchの違いは、アンカーを追加するために正規表現を変更する必要があるということです。どちらのメソッドも、私の意図をすぐに表現することも、ブール値を返すこともありません。つまり、OptionからBooleanに移行する必要があります(問題はありませんが、さらに混乱します)。
mkneissl 2010年

1
@mkneissl Javaの概念は嫌いmatchesですが、大丈夫です。用としてOptionBoolean、追加nonEmpty最後に、あなたが得られますBoolean
ダニエルC.ソブラル2010年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.