【问题标题】:VisualWorks - Find characters in string and replace themVisualWorks - 在字符串中查找字符并替换它们
【发布时间】:2019-04-29 13:43:32
【问题描述】:

我有一句话。起初,没有字母,只有?。例如,单词“town”会显示为“????”。 然后用户猜测字母,如果他确定它,它会从 ?到实际的字母。 例如,如果他猜 t,它看起来像这样 't???'。

问题是,我不知道如何遍历字符串并将其划分为字符。如果我以某种方式做到了,我无法在新字符串中更改它。

应该看起来像这样。

word do: [ :c | 
          c = guessedChar
                ifTrue[mask := mask, guessedChar]
                ifFalse[mask := mask, '?']
            ].

mask 被初始化为 nil,因为word 的长度可以改变并且wordStringguessedChar 连接到 inputField,但它一次只包含一个字符。

最好是为每个guessedChar 执行一次,还是收集所有猜测的字符并每次都运行它?

【问题讨论】:

    标签: smalltalk visualworks


    【解决方案1】:

    StringCollectionCharacter 对象。因此,您也可以使用适用于其他集合的相同方法(例如 #select:#collect:#reject:

    guessedCharacters := 'ts'.
    mask := word collect:[:each | (guessedCharacters includes: each)
                                     ifTrue:[each]
                                     ifFalse:[$?]].
    

    请注意't'StringCharacter t。 Character 可以用 $ 前缀作为文字字符 $t 编写。

    由于StringSequenceableCollection 的子类,您可以通过, 连接两个字符串。但是,您不能连接 StringCharacter

    相反,您可以使用#copyWith:Character 附加到String。结果是一个新的String,它不会修改现有的实例。

    【讨论】:

    • 这个也可以,而且清晰多了。然而,当新的 guessedChar 进来时,它仍然忘记了前一个。如何让它记住所有猜测的字符?
    • 也许您可以解释一下您尝试实现的目标,以便我们提出更好的建议。从您的其他 cmets 我认为 guessedChar 是连接到输入字段的 ValueHolder?它似乎包含String 而不仅仅是Character。所以你已经有了一个可以测试的字符列表。
    • guessedChar 连接到输入字段,但它只包含Character,因为您不能在其中输入多个字符。但是,是的,当用户赋予新角色时,我必须针对旧角色和新角色对其进行测试。我认为它可以在没有列表的情况下工作,只需一次添加一个字符
    • 不要使用“我可以在没有 x 的情况下编写它”来实现您的代码。编写代码,使其易于理解。您可以查看您的旧代码并问自己:我仍然理解我在这里编写的所有内容吗?如果没有,为什么不呢。如果您认为您的实现过于复杂(但可以工作!)请尝试清理它,但不要在您首先使其工作之前进行清理。
    • 您确定输入字段中有Character 吗?据我所知,您不能选择Character 作为类型,只能选择String。即使您设法将其大小限制为 1,它仍然是 String
    【解决方案2】:

    你可以使用

    word doWithIndex: [:c :i | c = guess ifTrue: [mask at: i put: c]]
    

    相当于:

    i := 1.
    word do: [:c |
      c = guess ifTrue: [mask at: i put: c].
      i := i + 1]
    

    除了你不必初始化和递增i(这更容易出错,更冗长)


    附录

    鉴于String 的实例不能增长或改变它们的大小,这是不可变的,我假设可能改变的是变量word。在这种情况下,您应该相应地初始化mask,因此两个字符串始终保持相同的长度。像这样:

     word: aString
       word := aString.
       mask := word copy atAllPut: $?
    

    如果你还想保留已经猜到的字符:

     word: aString
       | guessed |
       word := aString.
       guessed := mask reject: [:c | c = $?].
       mask := word copy atAllPut: $?.
       guessed do: [:c | self try: c].
    

    其中#try:是我们之前的方法

    try: aCharacter
      word doWithIndex: [:c :i | c = aCharacter ifTrue: [mask at: i put: c]]
    

    (如果需要,您可能想uppercase事物)

    【讨论】:

    • 谢谢你,但它不太奏效。它给了我“一个UserMessage('字符串只存储字符',#errStoreCharacters,#dialogs)”。我用了“guessedChar value asUppercase”而不是“guess”和doWithIndex,因为大众没有withIndexDo,但其他都一样
    • 现在我有这个代码word doWithIndex: [:c :i | c = guessedChar value asUppercase ifTrue: [mask at: i put: c] ifFalse: [mask:= mask, '?']].,但是当字符被正确猜到时它不会改变
    • 我已将答案修改为使用doWithIndex:。另请注意,我的代码假定wordString。如果不是,那么块参数c 将不是Character。在您的情况下,word 是什么?
    • 如果mask 已初始化为所有?,则当guess 不匹配时,您无需执行任何操作。在这种情况下你想做什么?
    • 它是这样定义的word := 'town' asUppercase.所以它应该是String
    【解决方案3】:
    "initially"
    actualWord := 'phlebotomy'.
    actualMask := actualWord collect: [:ch| $?].
    
    "after each guess"
    word := actualWord readStream.
    mask := actualMask readStream.
    newMask := WriteStream on: String new.
    [ word atEnd
    ] whileFalse:
        [ nextCh := word next = guessedCharcter
                      ifTrue: [mask skip. guessedCharacter]
                      ifFalse: [mask next].
          newMask nextPut: nextCh
        ].
    actualMask := newMask contents
    

    【讨论】:

      猜你喜欢
      • 2016-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-26
      • 2015-06-12
      相关资源
      最近更新 更多