【问题标题】:Regex Replace string between C Block comments正则表达式替换 C 块注释之间的字符串
【发布时间】: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# 正则表达式中的特殊字符,但星号 '*' 是(在所有正则表达式中)。

标签: c# regex string replace


【解决方案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*
      • 在零次和无限次之间,尽可能多次,按需回馈(贪婪)*
    • 匹配字符“*”字面意思\*
    • 匹配字符“/”字面意思/

注意事项

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

所以这会起作用:

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

这不会:

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

【讨论】:

  • Dean,这对大多数事情都很有效,但是当表达式本身有正斜杠时,它似乎不起作用。我修改了我的问题来说明。
  • @audiFanatic 我已经添加了我在未经批准的问题编辑中找到的示例,我将尝试更新我的答案以反映您提供的其他失败案例。
  • @audiFanatic 更新了替代方案并添加了更多注释。
猜你喜欢
  • 2017-11-16
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 2018-07-13
  • 2015-03-26
  • 2013-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多