С++ 11 regex: после группы захвата в строке замены

В моем выражении regex_replace используется группа $1 прямо перед символом '0' в заменяющей строке:

#include <iostream>
#include <string>
#include <regex>

using namespace std;

int main() {
    regex regex_a( "(.*)bar(.*)" );
    cout << regex_replace( "foobar0x1", regex_a, "$10xNUM" ) << endl;
    cout << regex_replace( "foobar0x1", regex_a, "$1 0xNUM" ) << endl;
}

Вывод:

xNUM
foo 0xNUM

Я пытаюсь получить вывод foo0xNUM без промежуточных пробелов.

Как защитить имя группы $1 от следующего символа в строке подстановки?

Ответ 1

Вам разрешено указывать $n или $nn для ссылки на захваченный текст, поэтому вы можете использовать формат $nn (здесь $01), чтобы избежать захвата 0.

cout << regex_replace( "foobar0x1", regex_a, "$010xNUM" ) << endl;

Ответ 2

Guvante предоставил решение для этой проблемы.

Однако является ли поведение корректным в соответствии со спецификацией?

Чтобы начать с вывода. Да, решение имеет четко определенное поведение.

Спецификация С++

Документация format_default, которая определяет правила ECMA для интерпретации строки формата, указывает на раздел 15.5.4.11 ECMA-262.

Спецификация ECMA-262

Согласно таблице 22 в Раздел 15.5.4.11 спецификации ECMA-262

$n

n-й захват, где n - одна цифра в диапазоне от 1 до 9 и $n, не следует десятичной цифрой. Если n ≤ m и n-й захват undefined, используйте вместо этого пустую строку. Если n > m, результат определяется реализацией.

$nn

nnth capture, где nn - двузначное десятичное число в диапазоне от 01 до 99. Если nn ≤ m и nnth-захват undefined, используйте вместо этого пустую строку. Если nn > m, результат определяется реализацией.

Переменная m определена в предыдущем абзаце в том же разделе:

[...] Пусть m - количество скобок слева в скобках в searchValue (используя NcapturingParens, как указано в 15.10.2.1).

Заменительная строка в вопросе "$10xNUM"

Вернуться к коду в вопросе:

cout << regex_replace( "foobar0x1", regex_a, "$10xNUM" ) << endl;

Так как за $1 следует 0, его нужно интерпретировать как второе правило $nn, так как первое правило запрещает любую цифру следовать за $n. Однако, поскольку шаблон имеет только 2 группы захвата (m = 2) и 10 > 2, поведение определяется реализацией в соответствии со спецификацией.

Мы можем увидеть эффект предложения, определяемого реализацией, путем сравнения результата функционально эквивалентного кода JavaScript в Firefox 37.0.1:

> "foobar0x1".replace(/(.*)bar(.*)/g, "$10xNUM" )
< "foo0xNUM"

Как вы можете видеть, Firefox решил интерпретировать $10 как значение первого захвата группы $1, а затем фиксированную строку 0. Это допустимая реализация в соответствии со спецификацией при условии в $nn.

Замена строки в ответе Гуванте: "$010xNUM"

То же, что и выше, используется предложение $nn, так как предложение $n запрещает любую цифру. Поскольку 01 in $01 меньше числа групп захвата (m = 2), поведение хорошо определено, что должно использовать содержимое группы захвата 1 при замене.

Поэтому ответ Guvante вернет тот же результат на любой компилятор С++ жалобы.

Ответ 3

Я попытался найти метод простого экранирования пространства или чего-то другого, чтобы он не печатался, но я не смог.

Однако бит, который вы пытаетесь добавить, может быть просто добавлен в конец вывода регулярного выражения:

cout << regex_replace( "foobar0x1", regex_a, "$1" ) << "0xNUM" << endl;

Вышеупомянутая строка даст вам нужный результат.