Regex Заменить строку между комментариями блока C - PullRequest
0 голосов
/ 09 мая 2019

Просто для ясности, прежде чем я начну свой запрос, у меня есть пример C-кода, который я пытаюсь изменить с помощью регулярных выражений C #. Я не задаю вопрос о C, я просто использую C # для автоматической генерации C-файла с использованием регулярных выражений.

Я пытаюсь написать регулярное выражение, которое заменит подстроку между двумя совпадающими строками (тегами). Я следовал вместе с этим вопросом , но я думаю, что потерпел неудачу, потому что мои «теги» принимают форму блочных комментариев в стиле C (с обратными слешами и звездочками, которые являются специальными символами в регулярном выражении). В конечном итоге это будет использоваться для автоматизации замены определенных значений в исходном файле на языке C.

Это пример некоторых моих C-кодов:

SetKeyString("modelNumber", /* #ModelNumber#*/ config.modelNumber /*#ModelNumber#*/);
config.maxKV = /*#MaxKV#*/  88.88 /*#MaxKV#*/;  

Я хочу заменить config.modelNumber и 88.88 новыми значениями, полученными извне из файла XML.

Предположим, данные из моего XML-файла:

<ModelNumber>ABCDE</ModelNumber>
<MaxKV>99.99</MaxKV>

Полученный C-код должен быть

SetKeyString("modelNumber", /*#ModelNumber#*/ ABCDE /*#ModelNumber#*/);
config.maxKV = /*#MaxKV#*/ 99.99 /*#MaxKV#*/;   

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

string x = Regex.Replace(mainLines[i], @String.Format(@"?<=/*#{0}#*/)(\w+?)(?=/*#{0}#*/)", property.Name), "middle");

mainLines - отдельные строки моего C-файла, а property.Name - имя тега XML: ModelNumber или MaxKV (без символов на концах).


Обновление - Дополнительные примеры

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

    config.kvRampRate =         /*#KVRampRate#*/ (10.0 / config.maxKV * 4095) / 12.124567719929887 /*#KVRampRate#*/;
    config.maRampRate =     /*#MARampRate#*/ 1.0/config.maxMA * 4095 / /*mARampRate-->*/87.80017152658661 /*#MARampRate#*/;

1 Ответ

1 голос
/ 09 мая 2019

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

Итак, для конкретного примера "ModelNumber":

Регулярное выражение

(?<=/\*\s*(#ModelNumber#)\s*\*\/)(.+)(?=/\*\s*\k<1>\s*\*/)

Используйте

resultString = Regex.Replace(subjectString, @"(?<=/\*\s*(#ModelNumber#)\s*\*\/)(.+)(?=/\*\s*\k<1>\s*\*/)", " new value ");

Визуализация

Regex Visualisation

Регулярное выражение подробное описание

  • Утверждают, что приведенное ниже регулярное выражение может быть сопоставлено в обратном направлении в этой позиции (положительный взгляд сзади) (?<=/\*\s*(#ModelNumber#)\s*\*\/)
    • Соответствует символу «/» буквально /
    • Буквенно соответствует символу «*» \*
    • Соответствует одному символу, который является «пробельным символом» (любой разделитель Unicode, табуляция, перевод строки, возврат каретки, вертикальная табуляция, перевод формы, следующая строка) \s*
      • От нуля до неограниченного количества раз, столько раз, сколько возможно, отдача по мере необходимости (жадный) *
    • Подберите регулярное выражение ниже и запишите его совпадение в номер обратной ссылки 1 (#ModelNumber#)
      • Буквенно соответствует строке символов «# ModelNumber #» (с учетом регистра) #ModelNumber#
    • Соответствует одному символу, который является «пробельным символом» (любой разделитель Unicode, табуляция, перевод строки, возврат каретки, вертикальная табуляция, перевод формы, следующая строка) \s*
      • От нуля до неограниченного количества раз, столько раз, сколько возможно, отдача по мере необходимости (жадный) *
    • Буквенно соответствует символу «*» \*
    • Буквенно соответствует символу «/» \/
  • Подберите регулярное выражение, приведенное ниже, и запишите его совпадение в номер обратной ссылки 2 (.+)
    • Соответствует любому отдельному символу, который НЕ является символом разрыва строки (перевод строки) .+
      • От одного до неограниченного количества раз, столько раз, сколько возможно, отдача по мере необходимости (жадный) +
  • Утверждают, что приведенное ниже регулярное выражение может быть сопоставлено, начиная с этой позиции (положительный взгляд) (?=/\*\s*\k<1>\s*\*/)
    • Совпадение с символом «/» буквально /
    • Совпадение символа «*» буквально \*
    • Соответствует одному символу, который является «пробелом» (любой разделитель Юникода, табуляция, перевод строки, возврат каретки, вертикальная табуляция, перевод формы, следующая строка) \s*
      • От нуля до неограниченного количества раз, столько раз, сколько возможно, отдача по мере необходимости (жадный) *
    • Совпадение с тем же текстом, который был сопоставлен последним путем захвата группы номер 1 (с учетом регистра; не выполняется, если группа не участвовала в совпадении до сих пор) \k<1>
    • Соответствует одному символу, который является «пробельным символом» (любой разделитель Unicode, табуляция, перевод строки, возврат каретки, вертикальная табуляция, перевод формы, следующая строка) \s*
      • От нуля до неограниченного количества раз, столько раз, сколько возможно, отдача по мере необходимости (жадный) *
    • Соответствует символу «*» буквально \*
    • Соответствует символу «/» буквально /

Примечания

  1. Я оставлю вам использование @ String.Format
  2. Возможно, вы захотите добавить пробел по обе стороны от значения замены, чтобы оставить интервал между вашими «тегами» и строкой замены. В то время как предыдущая версия моего ответа работала над этим, это показало результат и не дало легкого ответа на ваши крайние случаи.
  3. Не забудьте "regex escape" заменить значение "@ String.Format", если есть вероятность, что оно содержит значения, подобные "regex".
  4. Используется «обратная ссылка», чтобы иметь только одну часть для форматирования / замены, это часть \k<1>.
  5. Поскольку это регулярное выражение должно захватывать что-то, чтобы замена работала, у вас должен быть хотя бы один символ между вашими тегами (подойдет один пробел).

Так что это будет работать:

/*#ModelNumber#*/ /*#ModelNumber#*/

И это не будет:

/*#ModelNumber#*//*#ModelNumber#*/

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