2008-10-23 3 views
5

Я пытаюсь изменить пользовательский ввод в форме подстановки ("*word*") в формат регулярных выражений. С этой целью я использую ниже код, чтобы сдирать '*' в начале и в конце строки, так что я могу добавить символы регулярных выражений на обоих концах:std :: string стереть последний символ не удается?

string::iterator iter_begin = expressionBuilder.begin(); 
string::iterator iter_end = expressionBuilder.end(); 
iter_end--; 
if ((char)*iter_begin == '*' && (char)*iter_end == '*') 
{ 
    expressionBuilder.erase(iter_begin); 
    expressionBuilder.erase(iter_end); 
    expressionBuilder = "\\b\\w*" + expressionBuilder + "\\w*\\b"; 
} 

Однако вызов "expressionBuilder.erase(iter_end)"не стереть конечный '*' из входной строки, поэтому я завершаю неправильное регулярное выражение. Что я здесь делаю неправильно? "(char)*iter_end == '*'" должен быть правдой для кода внутри исполняемого файла if (что он делает), так почему же не работает тот же самый итератор при передаче для удаления()?

ответ

3

Try стирая их в обратном порядке:

expressionBuilder.erase(iter_end); 
expressionBuilder.erase(iter_begin); 

После стирания первый *, iter_end относится к одному символу за конец строки в вашем примере. STL documentation указывает, что итераторы недействительны на erase(), поэтому технически мой пример неверен, но я считаю, что он будет работать на практике.

+0

К счастью, со строками, вам не нужно использовать итераторы, большинство функций имеют форму, которая принимает индекс вместо этого. Тем не менее, как вы говорите, даже с индексированным стиранием все равно нужно сделать «назад к фронту». – 2008-10-23 19:50:48

+0

P4tXrx5jrMlbhyludk9pxHBT30kGHo9n: вы правы в end(), но там есть iter_end--, который смотрит на фактический последний символ строки. – 2008-10-23 19:54:03

+0

Это имеет смысл, и реверсирование заказа действительно решило проблему. Благодаря! – jeffm 2008-10-23 19:56:31

1

(пересмотрено, поскольку я пропустил линию iter_end--).

Возможно, вам нужна инструкция if, которая проверяет только *iter_begin == '*', а затем вызывает find(), чтобы получить другой '*'. Или вы можете использовать rbegin(), чтобы получить «начальный итератор последовательности в обратном порядке», продвиньте его один, а затем вызовите base(), чтобы превратить его в обычный итератор. Это даст вам последний символ в последовательности.


Еще лучше, std::string имеет rfind() and find_last_of() methods. Они дадут вам последние '*'. Вы также можете просто позвонить replace() вместо зачистки из '*' с, а затем добавить новый материал обратно в

7

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

  • использование недействительных итераторов после строки модифицируется
  • разыменования возможно недопустимые итераторов еще до того, как строка модифицируют (если строка пуста, например)
  • ошибки, если строка expressionBuilder содержит только петь le '*' character

Теперь два последних пункта не могут быть проблемой, если код, который использует snippet/подпрограмму, уже проверяет, что строка имеет не менее двух символов, но в случае, если это не ситуация, я считаю следующее более надежными в условиях произвольных значений для expressionBuilder:

// using the reverse iterator rbegin() is a nice easy way 
//  to get the last character of a string 

if ((expressionBuilder.size() >= 2) && 
    (*expressionBuilder.begin() == '*') && 
    (*expressionBuilder.rbegin() == '*')) { 

    expressionBuilder.erase(expressionBuilder.begin()); 

    // can't nicely use rbegin() here because erase() wont take a reverse 
    // iterator, and converting reverse iterators to regular iterators 
    // results in rather ugly, non-intuitive code 
    expressionBuilder.erase(expressionBuilder.end() - 1); // note - not invalid since we're getting it anew 

    expressionBuilder = "\\b\\w*" + expressionBuilder + "\\w*\\b"; 
} 

Обратите внимание, что этот код будет работать, когда expressionBuilder является "", "*" или "**" в том, что он не выполняет каких-либо действий, не определенных , Тем не менее, это может не привести к желаемым результатам в этих случаях (это потому, что я не знаю, что именно вы хотите в этих случаях). Модифицируйте в соответствии с вашими потребностями.

0

Минус обработки ошибок, вы, вероятно, просто сделать это следующим образом:

#include <iostream> 
#include <string> 
using namespace std; 

string stripStar(const string& s) { 
    return string(s.begin() + 1, s.end() - 1); 
} 

int main() { 
    cout << stripStar("*word*") << "\n"; 
} 
Смежные вопросы