std :: string удалить последний символ не удалось? - PullRequest
5 голосов
/ 23 октября 2008

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

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 (что он делает), так почему же не работает тот же итератор при передаче в erase ()?

Ответы [ 4 ]

7 голосов
/ 24 октября 2008

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

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

Теперь, последние два элемента могут и не быть проблемой, если код, использующий фрагмент / подпрограмму, уже проверяет, что строка содержит как минимум 2 символа, но в случае, если это не так, я считаю, что следующее более устойчивый к произвольным значениям для 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 равен "", "*" или "**", поскольку он не выполняет никаких неопределенных действий. Тем не менее, он может не дать желаемых результатов в этих случаях (это потому, что я не знаю точно, что вы хотите в этих случаях). Изменить в соответствии с вашими потребностями.

3 голосов
/ 23 октября 2008

Попробуйте стереть их в обратном порядке:

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

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

1 голос
/ 23 октября 2008

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

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


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

0 голосов
/ 24 октября 2008

За исключением обработки ошибок, вы могли бы просто сделать это так:

#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";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...