2012-10-12 41 views
6

Tôi muốn biết cách tôi có thể chia chuỗi bằng cách sử dụng nhiều dấu phân cách với Scala.Scala: cách chia nhỏ bằng cách sử dụng nhiều hơn một dấu phân cách

Ví dụ nếu tôi có một danh sách các delimiters:

List("Car", "Red", "Boo", "Foo") 

Và một chuỗi để thu hoạch:

Car foerjfpoekrfopekf Red ezokdpzkdpoedkzopke dekpzodk Foo azdkpodkzed 

Tôi muốn để có thể một cái gì đó đầu ra như:

List( ("Car", " foerjfpoekrfopekf "), 
    ("Red", " ezokdpzkdpoedkzopke dekpzodk "), 
    ("Foo", " azdkpodkzed")  
) 

Trả lời

1

một chút dài dòng, nhưng nó hoạt động:
KHÔNG DÙNG NỮA VERSION: (nó có lỗi, hãy để lại lỗi ở đây vì bạn đã chấp nhận câu trả lời)

def f(s: String, l: List[String], g: (String, List[String]) => Int) = { 
    for { 
     t <- l 
     if (s.contains(t)) 
     w = s.drop(s.indexOf(t) + t.length) 
    } yield (t, w.dropRight(w.length - g(w, l))) 
} 

def h(s: String, x: String) = if (s.contains(x)) s.indexOf(x) else s.length 

def g(s: String, l: List[String]): Int = l match { 
    case Nil => s.length 
    case x :: xs => math.min(h(s, x), g(s, xs)) 
} 

val l = List("Car", "Red", "Boo", "Foo") 

val s = "Car foerjfpoekrfopekf Red ezokdpzkdpoedkzopke dekpzodk Foo azdkpodkzed" 

đầu ra:

f(s, l, g).foreach(println) 
> (Car, foerjfpoekrfopekf) 
> (Red, ezokdpzkdpoedkzopke dekpzodk) 
> (Foo, azdkpodkzed) 

nó trả Array[String] thay vì danh sách. nhưng bạn cũng có thể làm như vậy: f(s, l, g).toList

CHỈNH SỬA: chỉ nhận thấy mã này là tốt nếu dấu phân tách chỉ xuất hiện một lần trong chuỗi. nếu đã xác định s như sau:

val s = "Car foerjfpoekrfopekf Red ezokdpzkdpoedkzopke dekpzodk Foo azdkpodkzed Car more..." 

tôi vẫn nhận được kết quả tương tự, thay vì cặp khác ("Car"," more...")

EDIT # 2: BUGLESS VERSION đây là đoạn cố định:

def h(s: String, x: String) = if (s.contains(x)) s.indexOf(x) else s.length 

def multiSplit(str: String, delimiters: List[String]): List[(String, String)] = { 
    val del = nextDelimiter(str, delimiters) 
    del._1 match { 
     case None => Nil 
     case Some(x) => { 
      val tmp = str.drop(x.length) 
      val current = tmp.dropRight(tmp.length - nextDelIndex(tmp,delimiters)) 
      (x, current) :: multiSplit(str.drop(x.length + current.length), delimiters) 
     } 
    } 
} 

def nextDelIndex(s: String, l: List[String]): Int = l match { 
    case Nil => s.length 
    case x :: xs => math.min(h(s, x), nextDelIndex(s, xs)) 
} 

def nextDelimiter(str: String, delimiters: List[String]): (Option[String], Int) = delimiters match { 
    case Nil => (None, -1) 
    case x :: xs => { 
     val next = nextDelimiter(str, xs) 
     if (str.contains(x)) { 
      val i = str.indexOf(x) 
      next._1 match { 
       case None => (Some(x), i) 
       case _ => if (next._2 < i) next else (Some(x), i) 
      } 
     } else next 
    } 
} 

đầu ra:

multiSplit(s, l).foreach(println) 
> (Car, foerjfpoekrfopekf) 
> (Red, ezokdpzkdpoedkzopke dekpzodk) 
> (Foo, azdkpodkzed) 
> (Car, more...) 

và bây giờ nó hoạt động :)

+0

cảm ơn bạn rất nhiều! đây là chính xác những gì tôi đã cố gắng để làm – Roch

+1

không có vấn đề ...Tôi thực sự thích nó :) –

+0

đó là khủng khiếp để đọc và - như đã được chứng minh - lỗi dễ bị –

7

Bạn có thể sử dụng danh sách để tạo cụm từ thông dụng và sử dụng phương thức tách:

val regex = List("Car", "Red", "Boo", "Foo").mkString("|").r 
regex.split("Car foerjfpoekrfopekf Red ezokdpzkdpoedkzopke dekpzodk Foo azdkpodkzed") 

Tuy nhiên, không cho bạn biết dấu phân cách nào được sử dụng ở đâu. Nếu bạn cần điều đó, tôi khuyên bạn nên thử thư viện phân tích cú pháp của Scala.

EDIT:

Hoặc bạn có thể sử dụng biểu thức thông thường để trích xuất một cặp tại một thời điểm như thế này:

def split(s:String, l:List[String]):List[(String,String)] = { 
    val delimRegex = l.mkString("|") 
    val r = "("+delimRegex+")(.*?)(("+delimRegex+").*)?" 
    val R = r.r 
    s match { 
    case R(delim, text, rest, _) => (delim, text) :: split(rest, l) 
    case _ => Nil 
    } 
} 
+0

Hoặc '.mkString (" \\ Q "," \\ E | \\ Q "," \\ E ")' để (hy vọng) giảm số lượng regex có thể khai thác. Không thực sự chắc chắn rằng điều này hoạt động, mặc dù. – Debilski

+1

chắc chắn, nếu danh sách đến từ một số nguồn bên ngoài, nhưng sau đó người ta nên sử dụng '.map (java.util.regex.Pattern.quote)' –

+0

Làm cho ý nghĩa hơn. Không biết điều đó. – Debilski

Các vấn đề liên quan