c++ замена однобайтового и двухбайтного символа

пишу программу, которая переводит транслит на кириллицу

std::vector <std::pair<std::string, std::string>> vec = {
    {"a", "а"},
    {"b", "б"},
    {"v", "в"},
    {"g", "г"},
    {"d", "д"},
    {"e", "е"},
    {"yo", "ё"},
    {"zh", "ж"},
    {"z", "з"},
    {"i", "и"},
    {"j", "дж"},
    {"k", "к"},
    {"l", "л"},
    {"m", "м"},
    {"n", "н"},
    {"o", "о"},
    {"p", "п"},
    {"r", "р"},
    {"s", "с"},
    {"t", "т"},
    {"u", "у"},
    {"f", "ф"},
    {"h", "х"},
    {"cz", "ц"},
    {"ch", "ч"},
    {"sh", "ш"},
    {"shh", "щ"},
    {"''", "ъ"},
    {"'", "ь"},
    {"y", "ай"},
    {"e'", "э"},
    {"yu", "ю"},
    {"ya", "я"},
    {"x", "кс"},
    {"w", "ви"},
    {"c", "к"},
    {"q", "к"},



    {"A", "А"},
    {"B", "Б"},
    {"V", "В"},
    {"G", "Г"},
    {"D", "Д"},
    {"E", "Е"},
    {"yo", "Ё"},
    {"zh", "Ж"},
    {"Z", "З"},
    {"I", "И"},
    {"J", "Дж"},
    {"K", "К"},
    {"L", "Л"},
    {"M", "М"},
    {"N", "Н"},
    {"O", "О"},
    {"P", "П"},
    {"R", "Р"},
    {"S", "С"},
    {"T", "Т"},
    {"U", "У"},
    {"F", "Ф"},
    {"H", "Х"},
    {"CZ", "Ц"},
    {"CH", "Ч"},
    {"SH", "Ш"},
    {"SHH", "Щ"},
    {"''", "ъ"},
    {"'", "ь"},
    {"Y", "Ай"},
    {"E'", "Э"},
    {"yu", "Ю"},
    {"ya", "Я"},
    {"X", "Кс"},
    {"W", "Ви"},
    {"C", "К"},
    {"Q", "к"}
};

std::string text = "savchik";
for (auto it : vec) {
    size_t f = std::string::npos;
    do {
        size_t f = text.find(it.first);
        if (f != std::string::npos)
            text = text.replace(f, it.first.length(), it.second);
    } while (f != std::string::npos);
}
std::cout << text << std::endl;

программа выводит вместо "савчик", "савкхик"


Ответы (1 шт):

Автор решения: Harry

Это еще не все неприятности :) -- добавьте, например, в конце ssavchiks — и вы получите савкхикs.

Ну, с этой неприятностью справиться просто, достаточно только объявить size_t f один раз вне цикла. Посмотрите внимательно: в проверке while (f != std::string::npos) участвует совсем не та переменная f, которая изменяется в цикле! И, кстати, компилятор должен был об этом предупредить — если, конечно, он настроен на выдачу всех предупреждений (а именно так он и должен быть настроен даже у опытного программиста).

Ну, а у вас проблема в том, что вы ищете по своему списку, нет ли того, что надо заменить, а в нем h идет до ch, вот и меняется сначала h, а потом остается "голая" c, которая меняется на к.

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

{"SHH", "Щ"},
{"shh", "щ"},
{"yu", "Ю"},
{"ya", "Я"},
{"yo", "Ё"},
{"zh", "Ж"},
{"CZ", "Ц"},
{"CH", "Ч"},
{"SH", "Ш"},
{"cz", "ц"},
{"ch", "ч"},
{"sh", "ш"},
{"yo", "ё"},
{"zh", "ж"},
{"yu", "ю"},
{"ya", "я"},
{"a", "а"},

Кстати, не стал исправлять — обратите внимание, что во второй части списка у вас куча повторов из-за того, что всякие yo, yu написаны со строчной буквы, а не с прописной!

Кстати, проблему вы бы увидели сразу, если бы, даже не умея работать с отладчиком, просто добавили отладочный вывод типа

    if (f != string::npos)
    {
        text = text.replace(f, it.first.length(), it.second);
        cout << "replace " << it.first << " for " << it.second
             << ", text = " << text << endl;
    }

а не бросались бы сразу в Интернет за решением тривиального вопроса. Так сказать, на работе вы тоже планируете решать проблемы таким образом? Напоминает маленького мальчика, который в ответ на "и как ты в армию пойдешь, если шнурки не научишься завязывать?" поясняет, что он с сотой для этого маму заберет :) Учитесь завязывать шнурки самостоятельно... Это не попытка наехать на вас, это попытка вам помочь в дальнейшей деятельности...

→ Ссылка