2014-07-21 64 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

相关问题