正则表达式替换C块注释之间的字符串

时间:2019-05-09 19:31:28

标签: c# regex string replace

为清楚起见,在我开始提问之前,我有一些示例C代码,我正在尝试使用C#正则表达式进行修改。我不是在问有关C的问题,我只是在使用C#使用正则表达式自动生成C文件。

我正在尝试编写一个正则表达式,它将替换两个匹配字符串(标签)之间的子字符串。我跟随this question,但是我认为我失败了,因为我的“标签”采用了C样式的块注释(在正则表达式中有反斜杠和星号)。最终,它将用于自动替换C源文件中的某些值。

这是我的一些C代码的示例:

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

我想用从XML文件从外部获得的新值替换config.modelNumber88.88

假设我的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标签的名称:ModelNumberMaxKV(结尾没有任何字符)


更新-其他示例

在对提议的解决方案进行进一步测试期间,发现了出现故障的边缘情况,因此这里提供了导致失败的其他示例输入:

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

1 个答案:

答案 0 :(得分:1)

我注意到您的示例中出现白色间距问题,而正则表达式中出现转义字符,这可能是导致问题的两个原因。

因此,对于“ 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*\*/)
    • 按字面意义/匹配字符“ /”
    • 从字面上\*匹配字符“ *”
    • 匹配单个字符,即“空白字符”(任何Unicode分隔符,制表符,换行符,回车符,垂直制表符,换页符,下一行)\s*
      • 在零次和无限制次数之间进行尽可能多的次数,并根据需要进行回馈(贪婪)*
    • 通过捕获第1组来匹配与最近匹配的相同文本(区分大小写;如果该组到目前为止尚未参加比赛,则失败)\k<1>
    • 匹配单个字符,即“空白字符”(任何Unicode分隔符,制表符,换行符,回车符,垂直制表符,换页符,下一行)\s*
      • 在零次和无限制次数之间进行尽可能多的次数,并根据需要进行回馈(贪婪)*
    • 从字面上\*匹配字符“ *”
    • 按字面意义/匹配字符“ /”

注释

  1. 我将使用@ String.Format留给您
  2. 您可能希望在替换值的两边添加一个空格,以保持“标签”和替换字符串之间的间距。虽然我的答案的先前版本可以解决此问题,但它却能提供出色的性能,并且无法轻松涵盖您的情况。
  3. 如果有可能包含“ regex”之类的值,请记住“ regex转义”“ @ String.Format”替换值。
  4. 这使用“后向引用”来仅格式化/替换一部分,即\k<1>部分。
  5. 由于此正则表达式必须捕获某些内容才能进行替换,因此您的标签之间必须至少有一个字符(一个空格即可)。

这将起作用:

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

这不会:

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