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

Posted

技术标签:

【中文标题】正则表达式替换 C 块注释之间的字符串【英文标题】:Regex Replace string between C Block comments 【发布时间】:2019-09-27 16:48:05 【问题描述】:

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

我正在尝试编写一个正则表达式,它将替换两个匹配字符串(标签)之间的子字符串。我跟着this question,但我认为我失败了,因为我的“标签”采用 C 样式块 cmets 的形式(它具有反斜杠和星号,它们是正则表达式中的特殊字符)。最终,这将用于自动替换 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#*/;

【问题讨论】:

您可以在正则表达式中使用反斜杠转义特殊字符:\*。您不想要零个或多个斜杠的序列,这就是您要匹配的内容:/*。你想要一个斜线后跟一个星号:/\* 这不是您问题的直接答案,但这是我在制作正则表达式时使用的。它使制作您可能想要的大多数正则表达式语句变得超级简单。 txt2re.com/index-csharp.php3 斜杠 '/' 不是 C# 正则表达式中的特殊字符,但星号 '*' 是(在所有正则表达式中)。 【参考方案1】:

我注意到您的示例中存在空白问题,并且正则表达式中存在转义字符,这可能是您的问题的几个原因。

那么对于“ModelNumber”的具体例子:

正则表达式

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

使用

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

可视化

正则表达式详细说明

断言下面的正则表达式可以在这个位置向后匹配(正向后看)(?&lt;=/\*\s*(#ModelNumber#)\s*\*\/) 匹配字符“/”字面意思/ 匹配字符“*”字面意思\* 匹配作为“空白字符”的单个字符(任何 Unicode 分隔符、制表符、换行符、回车符、垂直制表符、换页符、下一行)\s* 在零次和无限次之间,尽可能多次,按需回馈(贪婪)* 匹配下面的正则表达式并将其匹配捕获到反向引用编号 1 (#ModelNumber#) 从字面上匹配字符串“#ModelNumber#”(区分大小写)#ModelNumber# 匹配作为“空白字符”的单个字符(任何 Unicode 分隔符、制表符、换行符、回车符、垂直制表符、换页符、下一行)\s* 在零次和无限次之间,尽可能多次,按需回馈(贪婪)* 匹配字符“*”字面意思\* 匹配字符“/”字面意思\/ 匹配下面的正则表达式并将其匹配捕获到反向引用编号 2 (.+) 匹配任何不是换行符的单个字符(换行符).+ 在一次和无限次之间,尽可能多次,按需回馈(贪婪)+ 断言下面的正则表达式可以从这个位置开始匹配(正前瞻)(?=/\*\s*\k&lt;1&gt;\s*\*/) 匹配字符“/”字面意思/ 匹配字符“*”字面意思\* 匹配作为“空白字符”的单个字符(任何 Unicode 分隔符、制表符、换行符、回车符、垂直制表符、换页符、下一行)\s* 在零次和无限次之间,尽可能多次,按需回馈(贪婪)* 通过捕获组号 1 匹配最近匹配的相同文本(区分大小写;如果该组迄今未参与匹配则失败)\k&lt;1&gt; 匹配作为“空白字符”的单个字符(任何 Unicode 分隔符、制表符、换行符、回车符、垂直制表符、换页符、下一行)\s* 在零次和无限次之间,尽可能多次,按需回馈(贪婪)* 匹配字符“*”字面意思\* 匹配字符“/”字面意思/

注意事项

    我将把 @String.Format 的使用留给你 您可能希望在替换值的任一侧添加一个空格,以保持“标签”和替换字符串之间的间距。虽然我的答案的先前版本处理了这个问题,但它提供了性能并且没有轻松涵盖您的边缘情况。 如果“@String.Format”替换值有可能包含类似“regex”的值,请记住“regex escape”。 这使用“反向引用”来格式化/替换一个部分,即\k&lt;1&gt; 部分。 由于此正则表达式必须捕获某些内容才能使替换起作用,因此您的标签之间必须至少有一个字符(一个空格即可)。

所以这会起作用:

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

这不会:

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

【讨论】:

Dean,这对大多数事情都很有效,但是当表达式本身有正斜杠时,它似乎不起作用。我修改了我的问题来说明。 @audiFanatic 我已经添加了我在未经批准的问题编辑中找到的示例,我将尝试更新我的答案以反映您提供的其他失败案例。 @audiFanatic 更新了替代方案并添加了更多注释。

以上是关于正则表达式替换 C 块注释之间的字符串的主要内容,如果未能解决你的问题,请参考以下文章

SQL 注释中的 Java 正则表达式查找/替换模式

用java正则表达式提取java程序中的注释

正则表达式 - 如果模式匹配,则替换双引号之间的字符(逗号)

Java:使用正则表达式从块注释中去除斜线和星号

使用正则表达式解析 C 样式注释,避免回溯

PHP:正则表达式替换,同时忽略html标签之间的内容