2014-02-28 62 views
4

鑑於以下字符串單詞之後截斷字符串,...如何在斯卡拉

"localhost:9000/one/two/three" 

我想截斷它後的字two並獲得

"localhost:9000/one/two" 

我已經實施如下方法truncateBeforetruncateAfter

def truncateBefore(s: String, p: String) = { 
    s.substring(s.indexOf(p) + p.length, s.length) 
} 

def truncateAfter(s: String, p: String) = { 
    s.substring(0, s.indexOf(p) + p.length) 
} 

這些方法的工作,並返回預期的結果:

scala> truncateAfter("localhost:9000/one/two/three", "three") 
res1: String = localhost:9000/one/two 

scala> truncateBefore("localhost:9000/one/two/three", "three") 
res2: String = /three 

有沒有更好的辦法在Scala中做到這一點?最好用正則表達式?

+0

斯卡拉增加了一些不錯的東西Java的正則表達式,你當然可以用它來解決這個問題。 – joescii

+0

你想用一個呼叫返回兩個例子嗎?我認爲對於字符串操作,這個解決方案已經足夠好了 –

+0

@barnesjd,這個解決方案不使用正則表達式。 –

回答

2

第一個字面後分裂,沒有太多的正則表達式(雙關語意)。

scala> implicit class `split after`(val s: String) { 
    | def splitAfter(p: String): (String, String) = { 
    | val r = (Regex quote p).r 
    | r findFirstMatchIn s map (m => (s.substring(0, m.end), m.after.toString)) getOrElse (s, "") 
    | }} 
defined class split$u0020after 

scala> "abcfoodeffooghi" splitAfter "foo" 
res2: (String, String) = (abcfoo,deffooghi) 

scala> "abc*def" splitAfter "*" 
res3: (String, String) = (abc*,def) 
5

一個使用正則表達式選項

val beforeAfter = "(^.*two)(.*)$".r 

scala> val beforeAfter(after, before) = "localhost:9000/one/two/three" 
after: String = localhost:9000/one/two 
before: String = /three 

另一種選擇使用分裂

scala> "localhost:9000/one/two/three" split ("two") 
res0: Array[java.lang.String] = Array(localhost:9000/one/, /three) 

這些都不是的情況下,你不必在一個字two超級強大的解決方案輸入,但您可以相應地處理它...

還有一個使用正則表達式理解

scala> val beforeAfter = "(^.*two)(.*)$".r 
beforeAfter: scala.util.matching.Regex = (^.*two)(.*)$ 

scala> (for { 
    | matches <- beforeAfter.findAllIn("localhost:9000/one/two/three").matchData 
    | tokens <- matches.subgroups 
    | } yield tokens).toList 
res0: List[String] = List(localhost:9000/one/two, /three) 

這是安全的,如果沒有找到任何匹配:

scala> (for { 
    | match <- beforeAfter.findAllIn("localhost").matchData 
    | token <- match.subgroups 
    | } yield token).toList 
res1: List[String] = List() 
+0

@ j3d如果你走這條正則表達式的路線,你一定會想把'two'作爲一個參數。請確保使用正則表達式引號:'\\ Qtwo \\ E' – joescii

+0

@barnesjd可能模式#引用http://docs.oracle。com/javase/7/docs/api/java/util/regex/Pattern.html#quote(java.lang.String)稍後會更容易理解。 –

+0

我應該在哪裏放置這些引號?這個工作也沒有引號:val beforeAfter =(「(^。*」+ pattern +「)(。*)$」)。r – j3d

1

顯然效率不高,但它的作品。

scala> val url = "localhost:9000/one/two/three" 
url: String = localhost:9000/one/two/three 

scala> url.reverse.dropWhile(_ != '/').reverse 
res0: String = localhost:9000/one/two/ 

隨着指數:

scala> url.drop(url.reverse.indexOf('/')) 
res1: String = host:9000/one/two/three 
1

好的,謝謝大家......這裏是我的解決方案:

package object typeExtensions { 

    implicit class StringExtensions(val string: String) extends AnyVal { 

    def truncateAfter(pattern: String) = beforeAfter(pattern).map(_._1).getOrElse(string) 
    def truncateBefore(pattern: String) = beforeAfter(pattern).map(_._2).getOrElse(string) 

    private def beforeAfter(pattern: String) = { 
     if (string.contains(pattern)) { 
     val beforeAfter = ("(^.*" + Pattern.quote(pattern) + ")(.*)$").r 
     val beforeAfter(before, after) = string 
     Some(before, after) 
     } else None 
    } 
    } 
} 

地改善上述代碼是非常歡迎任何建議;-)