Замените tag1 tag2 tag3 на x1 x2 x3 - PullRequest
3 голосов
/ 05 апреля 2020

Я очень плохо знаком с regex и C ++, поэтому, пожалуйста, будьте осторожны со мной :)!


С учетом такой строки:

Ввод:

string s = "<ph0/>Hello StackOverflow! Thank you for helping! <ph1/>"

Я хочу заменить теги ph1 и ph2 для __ent_00000_ и __ent_00001_ соответственно, поэтому в конце я бы хотел, чтобы мои выходные данные были такими: Вывод:

string s = "__ent_00000_Hello StackOverflow! Thank you for helping! __ent_00001_"



И я также хотел бы сделать обратное, т.е. :

Ввод:

string s = "__ent_00000_Bye bye StackOverflow!  __ent_00001_"

Ввод:

string s = "<ph0/>Bye bye StackOverflow!  <ph1/>"


Это будет для любого произвольного числа тегов в строке ! Таким образом, идея заключается в том, чтобы просто заменить, но сохранить номер в целости и сохранности!

Моя идея состояла в том, чтобы regex_replace ( документация ), но, возможно, есть другой способ, я открыт для любого другого решения, которое работает!


Пример с несколькими тегами:

Ввод:

string input = "Restaurant is closed<ph0/> <ph1/> <ph2/> <ph3/> | <ph4/> <ph5/>alert<ph6/>We are not serving meals<ph7/> <ph8/> <ph9/> <ph10/> | <ph11/> <ph12/>sorry!"

Выход:

string output = "Restaurant is closed__ent_00000_ __ent_00001_ __ent_00002_ __ent_00003_ | __ent_00004_ __ent_00005_alert__ent_00006_We are not serving meals__ent_00007_ __ent_00008_ __ent_00009_ __ent_00010_ | __ent_00011_ __ent_00012_sorry!"

Спасибо и хорошего дня! :)

Ответы [ 2 ]

2 голосов
/ 05 апреля 2020

Вы настраиваете себя на неудачу, если ваше первое решение этой проблемы включает регулярные выражения. Пожалуйста, не надо! (где будет достаточно простой замены строки).

Если каждый тег встречается только один раз, все, что вам действительно нужно сделать, это вызвать string::replace на них. Даже если они встречаются несколько раз, используется алгоритм повышения replace_all().

1 голос
/ 16 апреля 2020

Первый случай - это действительно сценарий, в котором регулярное выражение C ++ не вполне способно обрабатывать «из коробки» из-за того, что вам нужно заменить захват в группе 1 нулевым левым числом. Требуется обратный вызов, и это может быть реализовано следующим образом:

template<class BidirIt, class Traits, class CharT, class UnaryFunction>
std::basic_string<CharT> regex_replace(BidirIt first, BidirIt last,
    const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
{
    std::basic_string<CharT> s;

    typename std::match_results<BidirIt>::difference_type
        positionOfLastMatch = 0;
    auto endOfLastMatch = first;

    auto callback = [&](const std::match_results<BidirIt>& match)
    {
        auto positionOfThisMatch = match.position(0);
        auto diff = positionOfThisMatch - positionOfLastMatch;

        auto startOfThisMatch = endOfLastMatch;
        std::advance(startOfThisMatch, diff);

        s.append(endOfLastMatch, startOfThisMatch);
        s.append(f(match));

        auto lengthOfMatch = match.length(0);

        positionOfLastMatch = positionOfThisMatch + lengthOfMatch;

        endOfLastMatch = startOfThisMatch;
        std::advance(endOfLastMatch, lengthOfMatch);
    };

    std::sregex_iterator begin(first, last, re), end;
    std::for_each(begin, end, callback);

    s.append(endOfLastMatch, last);

    return s;
}

template<class Traits, class CharT, class UnaryFunction>
std::string regex_replace(const std::string& s,
    const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
{
    return regex_replace(s.cbegin(), s.cend(), re, f);
}

std::string callback_to(const std::smatch& m) {
    stringstream s;
    char buffer[6];
    sprintf(buffer, "%05d", stoi(m.str(1)));
    s << "__ent_" << buffer << "_";
    return s.str();
}

Затем внутри основного кода вы можете использовать его как

std::string s = "Restaurant is closed<ph0/> <ph1/> <ph2/> <ph3/> | <ph4/> <ph5/>alert<ph6/>We are not serving meals<ph7/> <ph8/> <ph9/> <ph10/> | <ph11/> <ph12/>sorry!";
std::regex reg_to("<ph(\\d+)/>");
std::cout << regex_replace(s, reg_to, callback_to) << std::endl;
// => Restaurant is closed__ent_00000_ __ent_00001_ __ent_00002_ __ent_00003_ | __ent_00004_ __ent_00005_alert__ent_00006_We are not serving meals__ent_00007_ __ent_00008_ __ent_00009_ __ent_00010_ | __ent_00011_ __ent_00012_sorry!

. регулярное выражение простое, <ph(\d+)/>, соответствует <ph, 1+ цифр, захваченных в группе 1, а затем />. Внутри метода обратного вызова char buffer[6]; sprintf(buffer, "%05d", stoi(m.str(1))); подготовит число, а s << "__ent_" << buffer << "_"; получит поток строк, заполненный необходимыми данными.

Обратная замена проста и понятна:

std::string t = "__ent_00000_Bye bye StackOverflow!  __ent_00001_";
std::regex reg_from("__ent_0*(\\d+)_");
std::cout << std::regex_replace(t, reg_from, "<ph$1/>") << std::endl;
// => <ph0/>Bye bye StackOverflow!  <ph1/>

Шаблон __ent_0*(\d+)_ соответствует __ent_, затем ноль или более символов 0, затем захватывает 1+ цифр в группу 1 и затем сопоставляется _. Замена: <ph + значение группы 1 и текст />.

См. Демонстрационный пример regex .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...