2015-05-28 3 views
0

У меня вопрос о некотором фрагменте кода. Я выполнял упражнение в python о строках. Я придумал правильную логику, но по какой-то причине вывод внутри цикла for не возвращается правильно. Вместо этого возвращается глобальное значение. Я не слишком хорошо знаком с Python, но есть ли способ исправить это?Удалить повторяющиеся пробелы вручную в строке

def song_decoder(song): 
    global Ret 

    Ret = "" 

    Ret = song.replace("WUB", " ") 
    Ret = Ret.strip() 
    Ret += "1" 

    space = False 
    for i in range(0, len(Ret)): 
     if Ret[i] == "1": 
      Ret = Ret[:i] 
      break 
     elif Ret[i] == " ": 
      if space is False: 
       space = True 
      else: 
       if i+1 == len(Ret): 
        Ret = Ret[:i] 
       else: 
        Ret = Ret[:i] + Ret[(i+1):] 
     else: 
      space = False 

    return Ret 

код теста:

def test_song_decoder(self): 
    self.assertEquals(song_decoder("AWUBBWUBC"), "A B C","WUB should be replaced by 1 space") 
    self.assertEquals(song_decoder("AWUBWUBWUBBWUBWUBWUBC"), "A B C","multiples WUB should be replaced by only 1 space") 
    self.assertEquals(song_decoder("WUBAWUBBWUBCWUB"), "A B C","heading or trailing spaces should be removed") 

Второй тест не пройден, и 'A B C' вместо этого возвращается.

+0

Почему вы используете глобальный? –

+0

Просто чтобы убедиться, что эта песня не проблема. Я думал, что это может решить проблему, но это не так. – Kharrid

+0

Что вы на самом деле пытаетесь сделать? –

ответ

8

Прежде всего, вам не нужно здесь Ret. Так что лучше удалите эту строку.

Во-вторых, есть один тест недостающее который даст вам еще один намек:

>>> song_decoder("AWUBBWUBC") 
'A B C' 
>>> song_decoder("AWUBWUBBWUBWUBC") 
'A B C' 
>>> song_decoder("AWUBWUBWUBBWUBWUBWUBC") 
'A B C' 

Как вы можете видеть, два WUB s правильно заменить только один пробел. Проблема возникает, когда их три. Это должно дать вам подсказку о том, что обнаружение пространства не работает должным образом после того, как вы сделали замену. Причина этого на самом деле довольно проста:

# you iterate over the *initial* length of Ret 
for i in range(0, len(Ret)): 
    # ... 
    elif Ret[i] == " ": 
     if space is False: 
      space = True 
     else: 
      # when you hit a space and you have seen a space directly 
      # before then you check the next index… 
      if i+1 == len(Ret): 
       Ret = Ret[:i] 
      else: 
       # … and remove the next index from the string 
       Ret = Ret[:i] + Ret[(i+1):] 

    # now at the end of the loop, `i` is incremented to `i + 1` 
    # although you have already removed the character at index `i` 
    # making the next character you would have to check belong to 
    # index `i` too 

Таким образом, результатом является то, что вы пропустить символ, который приходит непосредственно после второго места (который вы удалить). Таким образом, невозможно обнаружить три пробела таким образом, потому что вы всегда пропускаете третий.

В общем, это очень плохая идея, чтобы перебирать то, что вы изменяете при этом. В вашем случае вы выполняете итерацию по длине строки, но строка на самом деле становится все короче. Поэтому вам действительно следует избегать этого.

Вместо итерации над Ret строкой, вы должны перебрать исходную строку, которые вы сохраняете постоянными:

def song_decoder(song): 
    # replace the WUBs and strip spaces 
    song = song.replace("WUB", " ").strip() 
    ret = '' 

    space = False 
    # instead of iterating over the length, just iterate over 
    # the characters of the string 
    for c in song: 
     # since we iterate over the string, we don’t need to check 
     # where it ends 

     # check for spaces 
     if c == " ": 
      # space is a boolean, so don’t compare it against booleans 
      if not space: 
       space = True 
      else: 
       # if we saw a space before and this character is a space 
       # we can just skip it 
       continue 
     else: 
      space = False 

     # if we got here, we didn’t skip a later space, so we should 
     # include the current character 
     ret += c 

    return ret 
+0

Большое спасибо! У меня было ощущение, что это связано с длиной строки, но я не мог на нее наложить. Спасибо за разъяснение. – Kharrid

+0

Это отличный пример того, что неправильно с кодом OP шаг за шагом (хотя все остальные права - гораздо проще сделать с помощью нескольких строк встроенных вызовов). Теперь, возможно, вы, возможно, сотрудничаете, чтобы сделать _question_ лучше и более подходящим для будущих читателей? Название, в частности, ужасно. –

+0

Извините, что на английском это не моя вещь. – Kharrid

2

Вы проходите через слишком много проблем, пытаясь свернуть несколько пробелов в один:

def song_decoder(song, delimiter="WUB"): 
    splits = song.split(delimiter) # instead of replacing, just split on your delimiter 
    cleaned = filter(None, splits) # remove empty elements caused by consecutive WUBs 
    return ' '.join(cleaned)  # join them up with a single space in between 
+1

Хотя это абсолютно правильно, это полностью нарушает цель ручной ручной манипуляции. – poke

+0

@poke Это зависит от того, почему упражнение выполняется.Если вам нужно научиться манипулированию строками в явном цикле, то абсолютно. Если вы узнаете нормальный лучший способ сделать это, писать половину страницы кода никому не помогает. –

+0

Достаточно честно, если это оригинальное намерение; Однако я оставлю это как пример того, как это сделать. – tzaman

Смежные вопросы