2014-12-18 7 views
1

Вот функция, которая заменит все экземпляры определенного слова (строки) другим словом (strng) в родительской строке.Преобразование цикла while в цикл while while

void clean(std::string &s,const std::string oldVal,const std::string newVal){ 
    std::string::size_type pos = 0; 

    while((pos = s.find(oldVal,pos)) != std::string::npos){ 
     s.replace(pos,oldVal.size(),newVal); 
     pos += newVal.size(); 
    } 
} 

Я довольно новичок в C++, и я нашел условие, которое немного сложно понять. Поэтому я решил сделать этот код более удобочитаемым. Я попытался сделать это в цикле do while. Однако программа потерпела крах. Выброс исключений out_of_range.
Что случилось с моим кодом? Я использовал ту же строку для проверки обеих функций.

void clean2(std::string &s,const std::string oldVal,const std::string newVal){ 
    std::string::size_type pos = 0; 
    do{ 
     pos = s.find(oldVal,pos); 
     s.replace(pos,oldVal.size(),newVal); 
     pos += newVal.size(); 
    }while(pos != std::string::npos); 
} 
+4

В цикле 'do-while' вам необходимо проверить' pos' перед его использованием. –

+0

Я проверяю его в состоянии while. –

+2

Я имею в виду, прежде чем вы используете 'pos' в функции' replace' и добавляете к нему. –

ответ

2

Это условие

pos != std::string::npos 

вы должны проверить после заявления

pos = s.find(oldVal,pos); 

В противном случае вы можете использовать недопустимое значение поз.

Так цикл в то время как в этом случае выглядит лучше, чем делать в то время как цикл. :)

Вместо подставляя время цикла для сделай в то время как цикл можно переписать функцию, используя для цикла. Например

void clean(std::string &s,const std::string oldVal,const std::string newVal) 
{ 
    for (std::string::size_type pos = 0; 
      (pos = s.find(oldVal, pos)) != std::string::npos; 
      pos += newVal.size()) 
    { 

     s.replace(pos, oldVal.size(), newVal); 
    } 
} 
+0

О, ладно. Теперь я понимаю. После последнего события oldval, пока условие все равно возвращает true и выполняет. И это испортит все. –

1

Существует причина, что и в то время как и делать-то время петли существует, и это не только для удобства чтения.
Основное отличие - это время проверки состояния.
Предыдущие версии работают в последовательности find -> test -> replace
Ваша версия работает в последовательности поиска -> replace -> test.

Что вы можете сделать, это добавить, если перед заменой, которая проверяет наличие одного и того же контура перед попыткой замены. Однако это менее эффективно и менее читаемо, чем оригинальная ИМО.

1

вам нужно как:

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

Другими словами:

void clean2(std::string &s,const std::string oldVal,const std::string newVal){ 
    std::string::size_type pos = 0; 
    do{ 
     pos = s.find(oldVal,pos); 
     if (pos != std::string::npos) 
     { 
      s.replace(pos,oldVal.size(),newVal); 
      pos += newVal.size(); 
     } 
    }while(pos != std::string::npos); 
} 

В качестве альтернативы, вы можете сделать что-то вроде этого:

while(true) 
{ 
    pos = s.find(oldVal,pos); 
    if (pos != std::string::npos) 
    { 
     s.replace(pos,oldVal.size(),newVal); 
     pos += newVal.size(); 
    } 
    else 
    { 
     break; 
    } 
} 

Или много других вариантов на том же тема.

+0

Почему я должен проверять pos в блоке do? Делайте, пока это работает (AFAIK): Выполняйте. Проверьте состояние, повторите операцию и т. Д. Поэтому, если мне гарантировано, что pos будет действительным в первый раз, зачем его проверять? Не будет ли в то время проверять его после выполнения выполнить в первый раз? –

+0

Я понимаю сейчас. –

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