通过正则表达式模式匹配使用 stringbuilder 替换多次出现的字符串

Posted

技术标签:

【中文标题】通过正则表达式模式匹配使用 stringbuilder 替换多次出现的字符串【英文标题】:Replacing mutiple occurrences of string using string builder by regex pattern matching 【发布时间】:2019-11-12 18:43:09 【问题描述】:

我们正在尝试用它们各自的“组”替换字符串构建器中的所有匹配模式(正则表达式)。

首先,我们试图找到该模式的所有出现次数并循环遍历它们(计数 - 终止条件)。对于每个匹配,我们都分配匹配对象并使用它们各自的组替换它们。

这里只替换第一个匹配项,从不替换其他匹配项。

      *str* - contains the actual string

      Regex - ('.*')\s*=\s*(.*)

匹配模式:

    'nam_cd'=isnull(rtrim(x.nam_cd),''), 
    'Company'=isnull(rtrim(a.co_name),'')

模式:使用https://regex101.com/创建

*matches.Count* - gives the correct count (here 2)


String pattern = @"('.*')\s*=\s*(.*)";
MatchCollection matches = Regex.Matches(str, pattern);
StringBuilder sb = new StringBuilder(str);
Match match = Regex.Match(str, pattern);

for (int i = 0; i < matches.Count; i++)

    String First = String.Empty;
    Console.WriteLine(match.Groups[0].Value);
    Console.WriteLine(match.Groups[1].Value);

    First = match.Groups[2].Value.TrimEnd('\r');
    First = First.Trim();
    First = First.TrimEnd(',');

    Console.WriteLine(First);

    sb.Replace(match.Groups[0].Value, First + " as " + match.Groups[1].Value) + " ,", match.Index, match.Groups[0].Value.Length);
    match = match.NextMatch();

当前输出:

SELECT DISTINCT
         isnull(rtrim(f.fleet),'') as 'Fleet' ,
        'cust_clnt_id' = isnull(rtrim(x.cust_clnt_id),'')

预期输出:

SELECT DISTINCT
 isnull(rtrim(f.fleet),'') as 'Fleet' ,
 isnull(rtrim(x.cust_clnt_id),'') as 'cust_clnt_id'

【问题讨论】:

请问初始文本是什么? @DmitryBychenko SELECT DISTINCT 'Fleet'=isnull(rtrim(f.fleet),''), 'cust_clnt_id' = isnull(rtrim(x.cust_clnt_id),'') 这是原始字符串。 这样的正则表达式解决方案太脆弱了。如果需要解析任意 SQL,则需要专用的解析器。您可以尝试Regex.Replace(s, @"('[^']+')\s*=\s*(\w+\((?&gt;[^()]+|(?&lt;o&gt;\()|(?&lt;-o&gt;\)))*\))", "\n $2 as $1") (demo),但仍然可能失败。 @WiktorStribizew :那个表达对我有用……谢谢。 【参考方案1】:

像这样的正则表达式解决方案太脆弱了。如果需要解析任意 SQL,则需要专用的解析器。 Parsing SQL code in C#中有如何正确解析SQL的例子。

如果您确定输入中没有“狂野”、不平衡的(),则可以使用正则表达式作为解决方法,一次性完成:

var result = Regex.Replace(s, @"('[^']+')\s*=\s*(\w+\((?>[^()]+|(?<o>\()|(?<-o>\)))*\))", "\n $2 as $1");

请参阅regex demo。

详情

('[^']+') - 捕获组 1 ($1):',除 ' 之外的 1 个或多个字符,然后是 ' \s*=\s* - = 包含 0+ 个空格 (\w+\((?&gt;[^()]+|(?&lt;o&gt;\()|(?&lt;-o&gt;\)))*\)) - 捕获组 2 ($2): \w+ - 1+ 字字符 \((?&gt;[^()]+|(?&lt;o&gt;\()|(?&lt;-o&gt;\)))*\) - 一个 (...) 子字符串,其中包含任意数量的平衡 (...)s(参见 my explanation of this pattern)。

【讨论】:

是否有任何通用正则表达式,我们也可以在其中处理 'City'=a.city_name , 'State'=a.st_cd, 等表达式,其中表别名是可选的。 @SaiKanth_K 也许Regex.Replace(s, @"('[^']+')\s*=\s*(\w+(?:\.\w+)*)", "$2 as $1")。见this demo。 Stribizew : 第一个表达式不提供像'City'=a.city_name 这样的输入 第二个表达式对第一种输入执行不正确的操作 下面是使用第二个表达式时的示例 (@"('[^']+')\s*=\s*(\w+(?:\.\w+)*)" ) 输入:@ 987654346@'Address3'=isnull(rtrim(a.addr_3_desc),''), 输出:a.addr_2_desc as 'Address2',isnull as 'Address3'(rtrim(a.addr_3_desc),''), @SaiKanth_K 你应该提到你想对两种类型的输入使用一个正则表达式。使用('[^']+')\s*=\s*(\w+(?:\.\w+)*(?:\((?&gt;[^()]+|(?&lt;o&gt;\()|(?&lt;-o&gt;\)))*\))?),见demo。 Stribizew : 对沟通不畅表示歉意....感谢您提供的解决方案正是我所需要的。

以上是关于通过正则表达式模式匹配使用 stringbuilder 替换多次出现的字符串的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式——更多匹配模式

Python: 正则表达式匹配多行,实现多行匹配模式

正则表达式

Java 正则表达式匹配基本多语言平面之外的字符

Java 正则表达式匹配基本多语言平面之外的字符

正则表达式的全局匹配模式