Smalltalk中子字符串的索引

时间:2018-07-04 17:43:40

标签: string smalltalk pharo visualworks dolphin-smalltalk

似乎Smalltalk实现缺少一种算法,该算法返回String中子字符串的所有索引。最相似的元素仅返回元素的一个索引,例如:firstIndexesOf:in:,findSubstring:,findAnySubstring:variant。

implementations in Ruby,但是第一个依靠Ruby hack,第二个不能忽略重叠的Strings,最后一个使用Enumerator类,我不知道如何将其转换为Smalltalk。我不知道这Python implementation是否是开始的最佳途径,因为考虑了两种情况(是否重叠)并且不使用正则表达式。

我的目标是找到提供以下行为的程序包或方法:

'ABDCDEFBDAC' indicesOf: 'BD'. "#(2 8)"

考虑重叠时:

'nnnn' indicesOf: 'nn' overlapping: true. "#(0 2)"

不考虑重叠时:

'nnnn' indicesOf 'nn' overlapping: false. "#(0 1 2)"

在Pharo中,当在Playground中选择了文本时,扫描仪会检测到该子字符串并突出显示匹配项。但是我找不到这个的String实现。

到目前为止,我的最大努力是在String(Pharo 6)中实现了该实现:

indicesOfSubstring: subString
  | indices i |

  indices := OrderedCollection new: self size.
  i := 0.
  [ (i := self findString: subString startingAt: i + 1) > 0 ] whileTrue: [
    indices addLast: i ].
  ^ indices

2 个答案:

答案 0 :(得分:5)

首先让我澄清一下,Smalltalk集合是基于1的,而不是基于0的。因此,您的示例应阅读

'nnnn' indexesOf: 'nn' overlapping: false. "#(1 3)"
'nnnn' indexesOf: 'nn' overlapping: true. "#(1 2 3)"

请注意,我也注意到了@lurker的观察(并且也对选择器进行了调整)。

现在,从您的代码开始,我将对其进行如下更改:

indexesOfSubstring: subString overlapping: aBoolean
  | n indexes i |
  n := subString size.
  indexes := OrderedCollection new.                            "removed the size"
  i := 1.                                                      "1-based"
  [
    i := self findString: subString startingAt: i.             "split condition"
    i > 0]
  whileTrue: [
    indexes add: i.                                            "add: = addLast:"
    i := aBoolean ifTrue: [i + 1] ifFalse: [i + n]].           "new!"
  ^indexes

请确保您编写了一些单元测试(不要忘了练习边框案例!)

答案 1 :(得分:1)

已编辑

如果您能在“更大的前景”中告诉我们您需要实现什么,那也很好。有时候Smalltalk提供了不同的方法。

Leandro在代码上击败了我(他的代码效率更高),但是我已经写了它,所以我也将分享它。听取他关于Smalltalk是基于1的=>重写示例的建议。

我以Smalltalk / X和Pharo 6.1为例。

代码为:

indexesOfSubstring: substringToFind overlapping: aBoolean

    | substringPositions aPosition currentPosition |

    substringPositions := OrderedSet new. "with overlap on you could get multiple same 
              positions in the result when there is more to find in the source string"

    substringToFindSize := substringToFind size. "speed up for large strings"
    aPosition := 1.

    [ self size > aPosition ] whileTrue: [
        currentPosition := self findString: substringToFind startingAt: aPosition.
        (currentPosition = 0) ifTrue: [ aPosition := self size + 1 ] "ends the loop substringToFind is not found"
                             ifFalse: [
                                 substringPositions add: currentPosition.
                                 aBoolean ifTrue: [ aPosition := aPosition + 1 ] "overlapping is on"
                                         ifFalse: [ aPosition := currentPosition + substringToFindSize ] "overlapping is off"
                             ]
    ].

    ^ substringPositions

我已解决一些发生在我身上的问题。不要忘了尽可能多地测试它!