2014-07-21 98 views
6

是否有一個Scala庫API方法(如果不是,一種慣用的方式)獲取一個更大的字符串(源)中的子字符串(目標)的所有索引列表?我試圖查看ScalaDoc,但無法找到任何明顯的東西。有很多方法做這麼多有用的事情,我猜我只是沒有提交正確的搜索條件。返回一個特定子字符串的所有索引

例如,如果我有一個「name:Yo,name:Jim,name:name,name:bozo」的源字符串,並使用「name:」的目標字符串,我想返回一個List(List)的[Int]列表(0,8,17,27)。

這裏是我快速的黑客來解決這個問題:

def indexesOf(source: String, target: String, index: Int = 0, withinOverlaps: Boolean = false): List[Int] = { 
    def recursive(index: Int, accumulator: List[Int]): List[Int] = { 
     if (!(index < source.size)) accumulator 
     else { 
     val position = source.indexOf(target, index) 
     if (position == -1) accumulator 
     else { 
      recursive(position + (if (withinOverlaps) 1 else target.size), position :: accumulator) 
     } 
     } 
    } 

    if (target.size <= source.size) { 
     if (!source.equals(target)) { 
     recursive(0, Nil).reverse 
     } 
     else List(0) 
    } 
    else Nil 
    } 

任何指導,你可以給我一個適當的標準庫入口點更換這將不勝感激。

UPDATE 2014 /月/ 22:

由悉達多杜塔的回答啓發,我地張緊了我的代碼。現在看起來是這樣的:

def indexesOf(source: String, target: String, index: Int = 0, withinOverlaps: Boolean = false): List[Int] = { 
    @tailrec def recursive(indexTarget: Int, accumulator: List[Int]): List[Int] = { 
     val position = source.indexOf(target, indexTarget) 
     if (position == -1) accumulator 
     else 
     recursive(position + (if (withinOverlaps) 1 else target.size), position :: accumulator) 
    } 
    recursive(index, Nil).reverse 
    } 

此外,如果我有「AAAAAAAA」源字符串,我使用「AA」的目標字符串,我會在默認情況下想拿回列表[INT]的列表(0,2,4,6)從搜索到的子字符串中跳過搜索。可以通過爲「aaaaaaaa」/「aa」情況下返回List(0,1,2,3,4,5,6)的withinOverlaps參數傳遞「true」來覆蓋默認值。

+1

沒有,不是 「a [標準]方法」。此外,由於這是工作代碼,因此它可能更適合代碼審查。 – user2864740

+0

@ chaotic3quilibrium任何方式,你可以BSD許可證的方法,所以老闆的人不生氣,如果我複製/適應它? :) – ericpeters

+0

@ericpeters我的理解是,任何在StackOverflow上發佈的代碼片段都可以假定爲公有領域;即不受任何許可約束限制,限制了您將剪輯剪切/粘貼/修改/定製到任何需要的上下文的能力。 – chaotic3quilibrium

回答

6

我總是傾向於將這類問題伸入正則表達式的竅門。我不會說這是正確,但它是一個很少的代碼地獄。 :)

val r = "\\Qname\\E".r 
val ex = "name:Yo,name:Jim,name:name,name:bozo" 

val is = r.findAllMatchIn(ex).map(_.start).toList 

引號\\Q\\E是沒有必要針對這種情況,但如果你正在尋找的字符串包含任何特殊字符,那麼這將是。

+0

非常好。在開發我的代碼Scala之前,我花了不到兩分鐘時間評估正則表達式的方法。有不止一種方式來綁定字符串搜索貓是很好的。 – chaotic3quilibrium

+0

順便說一句,如果你想使用純正則表達式(作爲來自其他源的未轉義的複製/粘貼),你也可以將第一行改爲「」「\ Qname \ E」「」。 Scala中的三重引號選項非常棒! – chaotic3quilibrium

1

一個小的代碼來獲得所有的索引
呼叫以下方法getAllIndexes(源,目標)

def getAllIndexes(source: String, target: String, index: Int = 0): List[Int] = { 
     val targetIndex = source.indexOf(target, index) 
     if(targetIndex != -1) 
      List(targetIndex) ++ getAllIndexes(source, target, targetIndex+1) 
     else 
      List() 
     } 
+0

這似乎是以相反的順序返回列表,即List(27,17,8,0),對不對?另外,您可以優化兩條路徑。第一個用「targetIndex :: get ...」替換「List(targetIndex)++ get ...」。第二個將「List()」替換爲「Nil」。 – chaotic3quilibrium

+1

否該方法按照索引即列表(0,8,17,27)以升序返回列表。優化是正確的。 –

+0

我剛剛嘗試過你的調用,並添加@tailrec註釋後,我得到一個編譯器錯誤,指出它不是尾遞歸(與++或::)。然而,你的小代碼激勵了我,所以我提供了一個更新來顯示我的代碼收緊。我還添加了另一個測試用例(「aaaaaaaa」,「aa」示例)以顯示可選withinOverlaps參數的好處。 – chaotic3quilibrium

相關問題