2010-01-14 33 views
11

Có cách nào đơn giản để trả về các kết quả regex dưới dạng mảng không?
Sau đây là cách tôi đang cố gắng trong 2.7.7:Scala regexps: cách trả về các kết quả phù hợp dưới dạng mảng hoặc danh sách

val s = """6 1 2""" 
val re = """(\d+)\s(\d+)\s(\d+)""".r 
for (m <- re.findAllIn (s)) println (m) // prints "6 1 2" 
re.findAllIn (s).toList.length // 3? No! It returns 1! 

Nhưng sau đó tôi đã cố gắng:

s match { 
    case re (m1, m2, m3) => println (m1) 
} 

Và điều này hoạt động tốt! m1 là 6, m2 là 1, vv

Sau đó, tôi tìm thấy một cái gì đó thêm vào sự nhầm lẫn của tôi:

val mit = re.findAllIn (s) 
println (mit.toString) 
println (mit.length) 
println (mit.toString) 

Đó in:

non-empty iterator 
1 
empty iterator 

"độ dài" cuộc gọi bằng cách nào đó sẽ thay đổi trạng thái của trình lặp. Chuyện gì đang xảy ra ở đây?

+0

Cuộc gọi của bạn để tìmAllIn (s) phù hợp với toàn bộ chuỗi, do đó danh sách kết quả của bạn không phải là Danh sách (6 1 2), nhưng thực sự là Danh sách ("6 1 2") chiều dài 1 –

Trả lời

24

Ok, trước hết, hiểu rằng findAllIn trả về một Iterator. An Iterator là một đối tượng tiêu thụ một lần. Bất cứ điều gì bạn làm với nó sẽ thay đổi nó. Đọc trên các trình vòng lặp nếu bạn không quen thuộc với chúng. Nếu bạn muốn nó có thể tái sử dụng, sau đó chuyển đổi kết quả của findAllIn thành List và chỉ sử dụng danh sách đó.

Bây giờ, có vẻ như bạn muốn tất cả phù hợp với nhóm, không phải tất cả các kết quả phù hợp. Phương thức findAllIn sẽ trả về tất cả các kết quả phù hợp của đầy đủ regex có thể được tìm thấy trên chuỗi. Ví dụ:

scala> val s = """6 1 2, 4 1 3""" 
s: java.lang.String = 6 1 2, 4 1 3 

scala> val re = """(\d+)\s(\d+)\s(\d+)""".r 
re: scala.util.matching.Regex = (\d+)\s(\d+)\s(\d+) 

scala> for(m <- re.findAllIn(s)) println(m) 
6 1 2 
4 1 3 

Thấy rằng có hai trận đấu, và cả hai đều không bao gồm "" ở giữa chuỗi, vì đó không phải là một phần của bất kỳ trận đấu.

Nếu bạn muốn các nhóm, bạn có thể nhận được chúng như thế này:

scala> val s = """6 1 2""" 
s: java.lang.String = 6 1 2 

scala> re.findFirstMatchIn(s) 
res4: Option[scala.util.matching.Regex.Match] = Some(6 1 2) 

scala> res4.get.subgroups 
res5: List[String] = List(6, 1, 2) 

Hoặc, sử dụng findAllIn, như thế này:

scala> val s = """6 1 2""" 
s: java.lang.String = 6 1 2 

scala> for(m <- re.findAllIn(s).matchData; e <- m.subgroups) println(e) 
6 
1 
2 

Phương pháp matchData sẽ làm cho một Iterator trả Match thay của String.

+0

Tôi không hiểu tại sao 'findAllIn' trả về một' MatchIterator', thay vì chỉ là một 'Iterator [Match]'. Thật khó hiểu vì một số phương pháp ở cấp thu không hoạt động. Ví dụ. nếu bạn thử gọi 'subgroups' như' re.findAllIn (s) .subgroups', nó sẽ thất bại, mặc dù 're.findAllIn (s) .groupCount' không khác (2.11.x) – Luciano

+0

@Luciano Sự khác biệt giữa' MatchIterator' và 'Iterator [Match]' là trước đây cũng là 'MatchData'. Tuy nhiên, scaladoc cảnh báo: Tất cả các phương thức được kế thừa từ 'scala.util.matching.Regex.MatchData' sẽ ném một' java.lang.IllegalStateException' cho đến khi matcher được khởi tạo. Trình ghép nối có thể được khởi tạo bằng cách gọi 'hasNext' hoặc' next() 'hoặc làm cho các phương thức này được gọi, chẳng hạn như bằng cách gọi' toString' hoặc lặp qua các phần tử của trình lặp. –

2

Hãy thử điều này:

val s = """6 1 2""" 
    val re = """\d+""".r 
    println(re.findAllIn(s).toList) // List(6, 1, 2) 
    println(re.findAllIn(s).toList.length) // 3 

Và, nếu bạn thực sự cần một danh sách các nhóm phù hợp trong một Regex singe:

val s = """6 1 2""" 
    val Re = """(\d+)\s(\d+)\s(\d+)""".r 
    s match { // this is just sugar for calling Re.unapplySeq(s) 
     case Re([email protected]_*) => println(mg) // List(6, 1, 2) 
    } 
9

Có sự khác biệt giữa cách unapplySeq giải thích nhóm mulitple và làm thế nào findAllIn. findAllIn quét mẫu của bạn qua chuỗi và trả về từng chuỗi phù hợp (tiến theo kết quả phù hợp nếu thành công hoặc một ký tự nếu nó không thành công).

Vì vậy, ví dụ:

scala> val s = "gecko 6 1 2 3 4 5" 
scala> re.findAllIn(s).toList 
res3: List[String] = List(6 1 2, 3 4 5) 

Mặt khác, unapplySeq giả một trận đấu hoàn hảo vào chuỗi.

scala> re.unapplySeq(s) 
res4: Option[List[String]] = None 

Vì vậy, nếu bạn muốn phân tích các nhóm mà bạn đã chỉ định trong chuỗi regex chính xác, hãy sử dụng unapplySeq. Nếu bạn muốn tìm các tập hợp con của chuỗi trông giống như mẫu regex của bạn, hãy sử dụng findAllIn. Nếu bạn muốn làm cả hai, chuỗi chúng mình:

scala> re.findAllIn(s).flatMap(text => re.unapplySeq(text).elements) 
res5: List[List[String]] = List(List(6, 1, 2), List(3, 4, 5)) 
Các vấn đề liên quan