Làm thế nào để kiểm tra xem một Chuỗi có hoàn toàn khớp với một Regex trong Scala hay không?


80

Giả sử tôi có một mẫu Regex mà tôi muốn kết hợp nhiều Chuỗi với nhau.

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

Tôi chỉ muốn kiểm tra xem một Chuỗi nhất định có khớp hoàn toàn với Regex hay không. Cách hay và thành ngữ để làm điều này trong Scala là gì?

Tôi biết rằng tôi có thể khớp mẫu trên Regexes, nhưng về mặt cú pháp, điều này không hài lòng lắm trong trường hợp này, vì tôi không có nhóm nào để trích xuất:

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

Hoặc tôi có thể quay trở lại mẫu Java cơ bản:

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

mà cũng không phải là thanh lịch.

Có giải pháp nào tốt hơn không?


Tôi nghĩ "5" match { case Digit() => true case _ => false }sẽ đẹp hơn so với việc sử dụng đối tượng mẫu bên dưới.
Mygod,

Câu trả lời:


66

Trả lời câu hỏi của riêng tôi, tôi sẽ sử dụng "mô hình thư viện của tôi"

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

và sử dụng nó như thế này

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

trừ khi ai đó đưa ra giải pháp tốt hơn (tiêu chuẩn).

Ghi chú

  • Tôi đã không ma cô Stringđể hạn chế phạm vi của các tác dụng phụ tiềm ẩn.

  • unapplySeq không đọc rất tốt trong bối cảnh đó.


Bạn có nghĩ đến tác dụng phụ cụ thể nào không? StringThay vào đó, tôi đã làm phiền , và điều này vẫn hoạt động tốt cho đến nay, bất chấp Stringchức năng thành viên của matches(regex: String).
KajMagnus

1
Tôi cũng có một chức năng misses. Match and missmatch :-) Thật khó chịu khi phải viết !s.matches(r)thay vì s misses r. Hmm
KajMagnus

1
Làm thế nào về tích hợp "5" matches "\\d"mà @polygenelubricants đề xuất?
Erik Kaplun

2
Dữ liệu khớp với một mẫu chứ không phải ngược lại. Scaladoc trên Regex gây ra vấn đề lớn về việc thiếu boolean cho các "trận đấu". Cá nhân tôi nghĩ bạn đã đổi một trận đấu đẹp cho một nếu-else. Nếu bạn không quan tâm đến các nhóm, hãy sử dụng case r(_*) =>.
som-snytt

Cần phải có một cách để làm điều này mà không cần nhập khẩu một thư viện bên ngoài ...
Jameela Huq

56

Tôi không biết rõ về Scala, nhưng có vẻ như bạn có thể làm được:

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

Người giới thiệu


25
Chà, điều đó hiệu quả, nhưng có nhược điểm là mẫu được biên dịch mỗi lần thử để phù hợp. Tôi muốn tránh điều đó vì lý do hiệu suất.
mkneissl

3
@mkneissl: thì có vẻ như bạn .pattern.matcher(text).matcheslà con đường để đi. Bạn có thể ẩn chi tiết trong một số phương thức tiện ích hoặc toán tử quá tải hoặc một cái gì đó nếu Scala hỗ trợ nó.
polygenelubricants,

4
Cảm ơn, đó là những gì tôi sẽ làm, hãy xem câu trả lời của tôi. Tôi hy vọng trả lời câu hỏi của chính mình được chấp nhận hành vi trên Stack Overflow ... Meta nói nó là ...
mkneissl

2
@ed. nó thậm chí còn chậm hơn và tồi tệ hơn, vậy tại sao?
Erik Kaplun

Liên kết được cung cấp làm tài liệu tham khảo đã bị hỏng
Valy Dia

13

Đối với kết quả phù hợp đầy đủ, bạn có thể sử dụng UpplySeq . Phương thức này cố gắng so khớp mục tiêu (toàn bộ trận đấu) và trả về các kết quả phù hợp.

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
Trong khi sự thật, công dụng chính của unapplySeq unapply và ngầm trong cases của một matchkhối.
Randall Schulz

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

Hừ! Tại sao lại đăng một bản sao của stackoverflow.com/a/3022478/158823 vào hai năm sau?
mkneissl

2
Câu hỏi ban đầu của bạn yêu cầu kết quả kết thúc bằng 'true' hoặc 'false', không phải 'Some' hoặc 'Không có'. Theo như tôi biết thìDefined không phải là một phần của thư viện cách đây 2 năm, nhưng có lẽ nó đã có. Dù sao, câu trả lời của tôi không phải là một bản sao ;-)
Jack

Tôi hiểu, nó không phải là một bản sao. Lấy làm tiếc.
mkneissl

1
Không có probs ;-) Sai lầm của tôi, tôi nên giải thích lý do tại sao tôi sử dụng isDefined trong câu trả lời của mình. Chỉ đưa ra mã như một câu trả lời nói chung là một ý tưởng tồi, vì vậy đó là điều tồi tệ của tôi.
Jack

1

Câu trả lời nằm trong regex:

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

Sau đó, sử dụng một trong các phương pháp hiện có.


3
Tôi không nghĩ rằng neo là vấn đề ở đây. String/Pattern/Matcher.matches, trong Java ít nhất, đã khớp toàn bộ chuỗi. Tôi nghĩ vấn đề chỉ là phong cách / thành ngữ cho regex-ing trong Scala, tức là "một trong những phương pháp hiện có" là gì.
polygenelubricants

@polygenelubricants Chà, Matcher.matcheslà một quang sai. Ok, nó có thể thực hiện một số tối ưu hóa, mặc dù tôi không biết liệu thư viện Java có thực sự tận dụng nó hay không. Nhưng cách tiêu chuẩn để Biểu thức chính quy thể hiện rằng bắt buộc phải có một kết quả khớp đầy đủ là sử dụng neo. Vì thư viện Scala không cung cấp một phương thức so khớp đầy đủ, nên cách thích hợp để làm điều đó là sử dụng neo. Hoặc đó, hoặc sử dụng thư viện Java.
Daniel C. Sobral

Neo không phải là vấn đề. Xem thêm ví dụ "123" trong câu trả lời của Vasil.
mkneissl

5
@Daniel Có thể bạn đang thiếu điểm - Câu hỏi của tôi là, nếu tôi chỉ cần biết liệu một regex có khớp hoàn toàn hay không, thì cách tốt để diễn đạt điều đó trong Scala là gì. Có rất nhiều giải pháp hoạt động, nhưng tóm lại, tôi nghĩ rằng có một phương pháp còn thiếu trong Regex chỉ làm được điều đó và không có gì khác. Để trả lời câu hỏi trong cam kết của bạn: Sự khác biệt từ unapplySeq với findFirstMatch là tôi phải thay đổi Regex để thêm các neo. Cả hai phương pháp đều không thể hiện ngay ý định của tôi cũng như không trả về giá trị boolean, đó là tôi phải chuyển từ Option sang Boolean (không vấn đề gì, nhưng thêm nhiều thứ lộn xộn hơn).
mkneissl

1
@mkneissl Tôi không thích khái niệm về Java matches, nhưng được. Đối với Optionvs Boolean, thêm nonEmptyvào cuối và bạn sẽ nhận được Boolean.
Daniel C. Sobral

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.