【问题标题】:Indices of a substring in SmalltalkSmalltalk 中子字符串的索引
【发布时间】:2018-07-04 17:43:40
【问题描述】:

Smalltalk 的实现似乎错过了返回字符串中子字符串的所有索引的算法。最相似的只返回一个元素的一个索引,例如:firstIndexesOf:in:、findSubstring:、findAnySubstring: variables。

implementations in Ruby,但第一个依赖于 Ruby hack,第二个无法忽略重叠字符串,最后一个使用 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

【问题讨论】:

  • 我可以鼓励您(尝试)自己实现该方法吗? SO 规则规定问题应该表现出一些编码工作;给我们看看你的。
  • 您的 overlappling: trueoverlapping: false 的示例结果似乎相反?
  • 当您对答案感到满意时,请不要忘记标记您的问题已回答!更多信息见stackoverflow.com/help/someone-answers

标签: string smalltalk pharo visualworks dolphin-smalltalk


【解决方案1】:

首先让我澄清一下 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

确保你编写了一些单元测试(不要忘记练习边界情况!)

【讨论】:

  • 感谢您的笔记。在 Smalltalk 中做[ (var := exp) > 0 ] ... 不是比[ var := exp. var > 0 ] 更有效
  • @user1000565 请为这个有趣的问题打开另一个问题。
  • 我刚刚想到分配i := aBoolean ... 是多余的。不是这样吗?只需aBoolean ifTrue: [i := i + 1] ifFalse: [i := i + n] 就足够了。
  • @tunkan,你是对的。我通常将作业移到块之外。我正在更改代码...谢谢!
【解决方案2】:

已编辑

如果您能告诉我们您需要在“更大的图景”中实现什么,那就太好了。有时 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

我已经解决了一些我遇到的问题。不要忘记尽可能多地测试它!

【讨论】:

  • 我认为currentPosition 不能是nil,因为当找不到子字符串时,findString:startingAt: 会以0 回答。无论如何,提供您的方法版本是个好主意。
  • @LeandroCaniglia 感谢您在startingAt 中纠正错字:)。当复制粘贴不能与 SO 一起正常工作时,它很糟糕。当然,当您什么也没找到时,您对 0 的看法是正确的。我已经调整了代码。 (我在工作区有代码,必须将其转换为选择器)。
猜你喜欢
  • 2020-05-23
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
  • 2021-02-24
相关资源
最近更新 更多