Smalltalk 中子串的索引
Indices of a substring in Smalltalk
似乎 Smalltalk 实现错过了一个算法,该算法 return 字符串中子字符串的所有索引。最相似的 returns 只有一个元素的一个索引,例如:firstIndexesOf:in:, findSubstring:, findAnySubstring: variants。
but the first one relies on a Ruby hack, the second one does not work ignoring overlapping Strings and the last one uses an Enumerator class which I don't know how to translate to Smalltalk. I wonder if this 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 (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
首先让我澄清一下,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
确保你写了一些单元测试(并且不要忘记练习边界案例!)
已编辑
如果您能告诉我们您需要在 "greater picture" 中实现什么,那也很好。有时 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
我已经解决了我遇到的一些问题。不要忘记尽可能多地测试它!
似乎 Smalltalk 实现错过了一个算法,该算法 return 字符串中子字符串的所有索引。最相似的 returns 只有一个元素的一个索引,例如:firstIndexesOf:in:, findSubstring:, findAnySubstring: variants。
我的目标是找到提供以下行为的包或方法:
'ABDCDEFBDAC' indicesOf: 'BD'. "#(2 8)"
当考虑重叠时:
'nnnn' indicesOf: 'nn' overlapping: true. "#(0 2)"
不考虑重叠时:
'nnnn' indicesOf 'nn' overlapping: false. "#(0 1 2)"
在 Pharo 中,当在 Playground 中选择文本时,扫描仪会检测子字符串并突出显示匹配项。但是我找不到这个的字符串实现。
到目前为止,我的最大努力在 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
首先让我澄清一下,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
确保你写了一些单元测试(并且不要忘记练习边界案例!)
已编辑
如果您能告诉我们您需要在 "greater picture" 中实现什么,那也很好。有时 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
我已经解决了我遇到的一些问题。不要忘记尽可能多地测试它!