Std :: string удалить последний символ не удается?

Я пытаюсь изменить ввод пользователя в форме подстановочного знака ("*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 ()?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
4 496
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

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

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

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

К счастью, со строками вам не нужно использовать итераторы, большинство функций имеют форму, которая вместо этого принимает индекс. Тем не менее, как вы говорите, даже при индексированном стирании это все равно нужно делать «задом наперед».

Chris Jester-Young 23.10.2008 23:50

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

Greg Hewgill 23.10.2008 23:54

В этом есть смысл, и изменение порядка решило проблему. Спасибо!

jeffm 23.10.2008 23:56

Извините, я пропустил строку со знаком «-».

Max Lybbert 24.10.2008 00:04

@Greg: в другом сообщении делается вывод, что итераторы после стертый недействительны. (stackoverflow.com/questions/62340/…)

xtofl 24.10.2008 00:47

@xtoff - это не относится к строке. Чтобы обеспечить поддержку строк с подсчетом ссылок, вызов любой неконстантной функции-члена (за исключением некоторых, которые ничего не делают, кроме возврата ссылок или итераторов) может сделать недействительными любые существующие итераторы.

Michael Burr 24.10.2008 01:02

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

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


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

Обратите внимание, что там есть iter_end--, который поддерживает один символ.

Greg Hewgill 23.10.2008 23:52

Вы пропустили "iter_end--;" строка, которая перемещает итератор обратно к последнему элементу? Я уверен, что ответ Грега верен, потому что итераторы строк - это в основном просто индексы, поэтому конечный индекс становится недействительным при первом стирании.

Roddy 23.10.2008 23:53

Я пытался избежать "find_last_of", потому что я уже знаю, где находится персонаж, но, возможно, я слишком сильно над этим подумал.

jeffm 23.10.2008 23:57

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

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

Спасибо. На данный момент я почти знаю, что строка не пуста или не "*", но я согласен с тем, что было бы лучше закодировать ее таким образом на случай, если что-то изменится позже.

jeffm 24.10.2008 01:55

Без обработки ошибок вы, вероятно, могли бы сделать это так:

#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";
}

Что, если вы позвоните stripStar("word") или даже stripStar("word*")? Я думаю, OP хочет такой универсальности.

Cosine 23.05.2014 04:19

Другие вопросы по теме