Средство ведения журнала для нашего проекта C++ будет реорганизовано, чтобы использовать повторяющиеся операторы сдвига влево (наподобие Qt qDebug()
) вместо вариативных функций в стиле printf.
Предположим, объект журнала называется logger
. Допустим, мы хотим показать ip и порт сервера, к которому мы подключились. В текущей реализации используется:
logger.logf("connected to %s:%d", ip, port);
После рефакторинга приведенный выше вызов станет таким:
logger() << "connected to" << ip << ":" << port;
Ручная замена всех этих вызовов была бы чрезвычайно утомительной и подверженной ошибкам, поэтому, естественно, я хочу использовать регулярное выражение. В качестве первого прохода я мог бы заменить вызов .logf(...)
, получив
logger() "connected to %s:%d", ip, port;
Однако переформатирование этой строки в синтаксис сдвига влево вызывает у меня проблемы. Мне удалось создать отдельные регулярные выражения для захвата заполнителей printf и аргументы, разделенные запятыми. Тем не менее, я не знаю, как правильно соотнести их.
Чтобы избежать повторения довольно громоздких регулярных выражений, я буду использовать заполнитель (printf)
для ссылки на заполнитель printf регулярное выражение (возвращающее именованную группу token
) и (args)
для ссылки на аргументы, разделенные запятыми. регулярное выражение (возвращающее именованную группу arg
). Ниже я приведу результаты различных попыток, примененных к соответствующей части вышеуказанной строки, то есть:
"connected to %s:%d", ip, port
/(printf)(args)/g
не дает совпадений./(printf)*(args)/g
создает два совпадения, содержащиеip
иport
в именованной группеarg
(но ничего вtoken
)./(printf)(args)*/g
достигает противоположного результата: он производит два совпадения, содержащие%s
и%d
в именованной группеtoken
, но ничего вarg
./(printf)*(args)*/g
возвращает 3 совпадения: первые два содержат%s
и%d
вtoken
, третье содержитport
вarg
. Однако регулярное выражение101 сообщает «20 совпадений — 207 шагов» и, похоже, соответствует каждому символу.Я подумал, что, возможно, мне нужно указать, что первая группа захвата всегда находится в двойных кавычках. Однако ни
/"(printf)"(args)/g
, ни/"(printf)(args)/g
не дают совпадений./(printf)"(args)/g
производит одно (неверное) совпадение, содержащее%d
в группеtoken
иip
вarg
, а подстановка занимает всю строку между этими двумя строками (поэтому ввод#
для строки подстановки приводит к"connected to %s:#, port
. Очевидно, это не желаемый результат, но это единственная версия, в которой я мог получить хотя бы обе именованные группы в одном матче.
Любая помощь приветствуется.
Отредактировано для исправления неправильного форматирования.
printf
:logger.logf("connected to %.*s:%-4d", 16, ip, port);
. - person dxiv   schedule 08.07.2016extra formatting
. Например,%.*s
— это обычный способprintf
строк, не заканчивающихся нулем (или, если быть педантичным, массивы символов). Игнорирование спецификатораprecision
изменяет не только форматирование, но и саму семантику в этих случаях. - person dxiv   schedule 08.07.2016logger.logf("a" "b" "\"");
Вероятно, проще написать небольшой посимвольный транслятор (например, на С++), чем правильно выполнять регулярные выражения. - person Gene   schedule 08.07.2016*
в регулярном выражении, пока не понял, что не могу вспомнить ни одного случая, когда они использовались. Быстрый просмотр кодовой базы подтвердил это: кажется, нигде не используются директивы форматирования*
. Между прочим, это означает, что количество заполнителей printf должно точно совпадать с количеством аргументов, что должно сделать решение (каким бы оно ни было) немного проще. - person   schedule 08.07.2016