2009-11-06 35 views
7

Tôi đang cố gắng nắm bắt các phần của một chuỗi nhiều hàng với một regex trong Scala. Các đầu vào có dạng:Scala Regex Nhiều khối Chụp

val input = """some text 
       |begin { 
       | content to extract 
       | content to extract 
       |} 
       |some text 
       |begin { 
       | other content to extract 
       |} 
       |some text""".stripMargin 

Tôi đã thử một vài khả năng mà nên làm cho tôi văn bản ra khỏi begin {} khối. Một trong số họ:

val Block = """(?s).*begin \{(.*)\}""".r 

input match { 
    case Block(content) => println(content) 
    case _ => println("NO MATCH") 
} 

Tôi nhận được NO MATCH. Nếu tôi thả \} regex trông giống như (?s).*begin \{(.*) và nó khớp với khối cuối cùng bao gồm } và "một số văn bản" không mong muốn. Tôi đã kiểm tra regex của mình tại rubular.com như với /.*begin \{(.*)\}/m và nó khớp với ít nhất một khối. Tôi nghĩ rằng khi Scala regex của tôi sẽ phù hợp với cùng tôi có thể bắt đầu sử dụng findAllIn để phù hợp với tất cả các khối. Tôi đang làm gì sai?

Tôi đã xem Scala Regex enable Multiline option nhưng tôi không thể quản lý để nắm bắt tất cả các lần xuất hiện của các khối văn bản, ví dụ: Seq[String]. Bất kỳ trợ giúp nào được đánh giá cao.

Trả lời

10

Khi Alex cho biết khi sử dụng đối sánh mẫu để trích xuất trường từ biểu thức chính quy, mẫu hoạt động như thể bị chặn (ví dụ: sử dụng ^$). Cách thông thường để tránh vấn đề này là sử dụng findAllIn trước tiên. Bằng cách này:

val input = """some text 
       |begin { 
       | content to extract 
       | content to extract 
       |} 
       |some text 
       |begin { 
       | other content to extract 
       |} 
       |some text""".stripMargin 

val Block = """(?s)begin \{(.*)\}""".r 

Block findAllIn input foreach (_ match { 
    case Block(content) => println(content) 
    case _ => println("NO MATCH") 
}) 

Nếu không, bạn có thể sử dụng .* ngay từ đầu và kết thúc để có được xung quanh hạn chế đó:

val Block = """(?s).*begin \{(.*)\}.*""".r 

input match { 
    case Block(content) => println(content) 
    case _ => println("NO MATCH") 
} 

Bằng cách này, bạn có thể muốn một khớp không háo hức:

val Block = """(?s)begin \{(.*?)\}""".r 

Block findAllIn input foreach (_ match { 
    case Block(content) => println(content) 
    case _ => println("NO MATCH") 
}) 
+0

Bạn có biết liệu tài liệu này có được ghi ở bất kỳ đâu không? –

+1

Cảm ơn Daniel cho câu trả lời chi tiết của bạn. Làm việc như một say mê. –

+0

Alex, tại thời điểm này, tôi không chắc chắn. Tôi đã làm rất nhiều với Regex, thậm chí mở rộng thư viện, rằng tôi thậm chí không thể nhớ những gì thư viện cung cấp hay không! Ví dụ, tôi sẽ viết 'Block findAllMatchesIn map (_ group 0)', khi tôi phát hiện ra phương thức này không tồn tại trong thư viện. –

1

Khi thực hiện trận đấu, tôi tin rằng cần có sự phù hợp hoàn toàn. trận đấu của bạn là tương đương với:

val Block = """^(?s).*begin \{(.*)\}$""".r 

Nó hoạt động nếu bạn thêm * vào phía sau:.

val Block = """(?s).*begin \{(.*)\}.*""".r 

tôi đã không thể tìm thấy bất kỳ tài liệu về vấn đề này, nhưng tôi đã gặp cùng này vấn đề.

+0

Yup, đó đã làm việc, cảm ơn. –

0

Là một bổ sung cho các câu trả lời khác, tôi muốn chỉ ra sự tồn tại của kantan.regex, cho phép bạn viết như sau:

import kantan.regex.ops._ 

// The type parameter is the type as which to decode results, 
// the value parameters are the regular expression to apply and the group to 
// extract data from. 
input.evalRegex[String]("""(?s)begin \{(.*?)\}""", 1).toList 

này sản lượng:

List(Success(
    content to extract 
    content to extract 
), Success(
    other content to extract 
)) 
Các vấn đề liên quan