正则表达式替换 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.modelNumber
和 88.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 标记的名称: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#*/;
【问题讨论】:
您可以在正则表达式中使用反斜杠转义特殊字符:\*
。您不想要零个或多个斜杠的序列,这就是您要匹配的内容:/*
。你想要一个斜线后跟一个星号:/\*
。
这不是您问题的直接答案,但这是我在制作正则表达式时使用的。它使制作您可能想要的大多数正则表达式语句变得超级简单。 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 ");
可视化
正则表达式详细说明
断言下面的正则表达式可以在这个位置向后匹配(正向后看)(?<=/\*\s*(#ModelNumber#)\s*\*\/)
匹配字符“/”字面意思/
匹配字符“*”字面意思\*
匹配作为“空白字符”的单个字符(任何 Unicode 分隔符、制表符、换行符、回车符、垂直制表符、换页符、下一行)\s*
在零次和无限次之间,尽可能多次,按需回馈(贪婪)*
匹配下面的正则表达式并将其匹配捕获到反向引用编号 1 (#ModelNumber#)
从字面上匹配字符串“#ModelNumber#”(区分大小写)#ModelNumber#
匹配作为“空白字符”的单个字符(任何 Unicode 分隔符、制表符、换行符、回车符、垂直制表符、换页符、下一行)\s*
在零次和无限次之间,尽可能多次,按需回馈(贪婪)*
匹配字符“*”字面意思\*
匹配字符“/”字面意思\/
匹配下面的正则表达式并将其匹配捕获到反向引用编号 2 (.+)
匹配任何不是换行符的单个字符(换行符).+
在一次和无限次之间,尽可能多次,按需回馈(贪婪)+
断言下面的正则表达式可以从这个位置开始匹配(正前瞻)(?=/\*\s*\k<1>\s*\*/)
匹配字符“/”字面意思/
匹配字符“*”字面意思\*
匹配作为“空白字符”的单个字符(任何 Unicode 分隔符、制表符、换行符、回车符、垂直制表符、换页符、下一行)\s*
在零次和无限次之间,尽可能多次,按需回馈(贪婪)*
通过捕获组号 1 匹配最近匹配的相同文本(区分大小写;如果该组迄今未参与匹配则失败)\k<1>
匹配作为“空白字符”的单个字符(任何 Unicode 分隔符、制表符、换行符、回车符、垂直制表符、换页符、下一行)\s*
在零次和无限次之间,尽可能多次,按需回馈(贪婪)*
匹配字符“*”字面意思\*
匹配字符“/”字面意思/
注意事项
-
我将把 @String.Format 的使用留给你
您可能希望在替换值的任一侧添加一个空格,以保持“标签”和替换字符串之间的间距。虽然我的答案的先前版本处理了这个问题,但它提供了性能并且没有轻松涵盖您的边缘情况。
如果“@String.Format”替换值有可能包含类似“regex”的值,请记住“regex escape”。
这使用“反向引用”来格式化/替换一个部分,即
\k<1>
部分。
由于此正则表达式必须捕获某些内容才能使替换起作用,因此您的标签之间必须至少有一个字符(一个空格即可)。
所以这会起作用:
/*#ModelNumber#*/ /*#ModelNumber#*/
这不会:
/*#ModelNumber#*//*#ModelNumber#*/
【讨论】:
Dean,这对大多数事情都很有效,但是当表达式本身有正斜杠时,它似乎不起作用。我修改了我的问题来说明。 @audiFanatic 我已经添加了我在未经批准的问题编辑中找到的示例,我将尝试更新我的答案以反映您提供的其他失败案例。 @audiFanatic 更新了替代方案并添加了更多注释。以上是关于正则表达式替换 C 块注释之间的字符串的主要内容,如果未能解决你的问题,请参考以下文章