使用C#和正则表达式从SQL select语句中删除别名

时间:2010-07-08 20:00:10

标签: c# .net regex

我正在学习正则表达式,而且我正在玩它们。我自己提出了一个练习,其中有一个方法可以删除SQL Select语句中的列别名。这应该是这样的:

  • 该方法可以删除SQL中的别名 select语句与AS关键字: “选择ColumnA AS A”
  • 该方法可以删除SQL中的别名 没有AS的select语句 keyword:“select ColumnB B”
  • 该方法可以删除SQL中的别名 select语句包含 “操作人物”(如 连接操作字符): “选择'你好'|| '世界!'AS HelloWorld”的

到目前为止,我已经创建了两种仅适用于特定情况的方法。以下代码总结了我所做的以及我所面临的问题。

static void Main(string[] args)
{
    string cols1 = "ColA as AliasA, ColB   AliasB  , As As ASasas, Asasasas as As";
    string cols2 = "'aaa' || 'bbb'  AS   AliasC , 'ccc' || 'ddd' AliasD";

    string answer1 = RemAliases(cols1);     // Works fine
    string answer2 = RemAliases2(cols2);    // Works fine
    string answer3 = RemAliases2(cols1);    // Doesn't work
    string answer4 = RemAliases(cols2);     // Doesn't work            
}

static string RemAliases2(string inputSql)
{
    string pattern1 = @"(.+)\s+AS\s+\w+";
    string replacement1 = "$1";
    string pattern2 = @"(.+)\s+\w+";
    string replacement2 = "$1";
    string result = Regex.Replace(inputSql, pattern1, replacement1, RegexOptions.IgnoreCase);
    result = Regex.Replace(result, pattern2, replacement2, RegexOptions.IgnoreCase);
    return result;
}

static string RemAliases(string inputSql)
{
    string pattern1 = @"(\w+)\s+AS\s+\w+";
    string replacement1 = "$1";
    string pattern2 = @"(\w+)\s+\w+";
    string replacement2 = "$1";
    string result = Regex.Replace(inputSql, pattern1, replacement1, RegexOptions.IgnoreCase);
    result = Regex.Replace(result, pattern2, replacement2, RegexOptions.IgnoreCase);
    return result;
}

我没想到“RemAliases()”与“cols2”一起正常工作,因为“\ w +”与“|”字符不匹配。虽然,我期待“RemAliases2()”也能正常使用“cols1”。有人可以给我一些帮助,以便知道为什么“RemAliases2()”对“cols1”案件不起作用吗?请随意提供关于我使用这些正则表达式的方式的任何其他建议。

提前致谢。

PS:我正在使用.NET 2.0

4 个答案:

答案 0 :(得分:0)

(.+)\s+AS\s+\w+的一个问题是(.+)是贪婪的。这意味着它将保持正常运行,直到它不再匹配任何更多的字符,这意味着换行。如果你放一个?在+之后,它会使它变得懒惰,所以它会在找到第一个空格后停止,因为空格与\ s匹配。

接下来的问题是。也匹配白色空间。所以,当你有ColB AliasB ,的情况时,它会继续运行,直到它得到一个“AS”来匹配正则表达式的下一部分。在这种情况下,它被发现作为下一组的一部分。所以,你最好不要像使用RemAliases函数那样使用\ w +。

就我现在所说的而言。如果我找到其他东西,我会稍后编辑。与此同时,既然你正在学习,这里有一个非常好的参考,我通常在我需要写一些正则表达式时使用:Regex Reference

答案 1 :(得分:0)

至于为什么RemAliases2不适用于你的cols1是。+是贪婪的 - 它需要尽可能多。

(.+)将采取整行。然后正则表达式引擎将退步以尝试匹配正则表达式的剩余部分。所以,比赛将是:

(.+) --> "ColA as AliasA, ColB   AliasB  , As As ASasas, Asasasas"
\s+  --> " "
AS   --> "as"
\s+  --> " "
\w+  --> "As"

我将正则表达式的每个部分划分为单独的行,并显示字符串中的部分在 - >之后的“”内部匹配。

您依次应用每个正则表达式,但它适用于整个字符串 - 它只是因为测试字符串中的文本顺序,它似乎工作 - 但它不会扩展一点都不。

一个可能更好的开始(对于案例)将是:

(.+?)(\s+as\s+\w+\s*)(,|$)

我已将+更改为非贪婪(+?),我在别名列名之后但在逗号(\ s *)之前添加了空格选项,并且我添加了逗号交替在行尾,正确结束表达式(,| $),这样你就可以为select子句中的每个字段多次迭代。

然而,这只做一个匹配,而不是多个匹配(注意我知道正则表达式而不是C#,所以我不能确切地说它在C#中是如何工作的,但概念非常普遍)。您需要多次遍历字符串,或使用全局标志调用该函数。 (在Java中,你可以通过调用replaceAll()而不是replace()来实现它 - 我假设C#有一个类似的构造。)

全局应用,并在替换字符串中插入$ 1和$ 3将得到修改后的cols1:

ColA,ColB AliasB,As,Asasasas

然后,你有没有AS的情况,这更难!

答案 2 :(得分:0)

为了使您的正则表达式可靠地工作,您需要更加努力地拼出它应该匹配的内容,而不是尝试使用.+的快捷方式。下面的解释是相当冗长的。这是构建正则表达式时我遵循的思维过程。

根据您的示例,您可以使用colA等标识符,也可以使用'aaa' || 'bbb'等单引号字符串连接。您可以将标识符与\w+匹配,将字符串与'[^']*'(?:\s*\|\|\s*'[^']*')*匹配。我对字符串的正则表达式允许连接任意数量的字符串,包括没有连接(即只有一个单引号字符串)。

要匹配这两者中的任何一个,我们可以使用\b\w+\s+|'[^']*'(?:\s*\|\|\s*'[^']*')*\s*。我在标识符之后添加了\s+,因为它必须与后面的空格分开。对于连接的字符串,\s*使分隔空格可选。

标识符或字符串可以选择后跟关键字As。如果关键字存在,则必须后跟空格。我们可以将其编码为(As\s+)?

最后,所有这些都是另一个标识符。这个很容易与\w+匹配。

总而言之,我们得到了这个正则表达式:

(\b\w+\s+|'[^']*'(?:\s*\|\|\s*'[^']*')*\s*)(As\s+)?\w+

我在第一部分附近放了一个捕获组。我们需要它来进行搜索和替换。仅使用列名称或字符串连接替换此正则表达式匹配会有效地删除“as”部分。替换文字只是$1

或者在C#中:

result = Regex.Replace(inputSql, 
    @"(\b\w+\s+|'[^']*'(?:\s*\|\|\s*'[^']*')*\s*)(As\s+)?\w+", "$1",
    RegexOptions.IgnoreCase);

答案 3 :(得分:0)

非正则表达式方法:

/// <summary>
/// Remove SQL aliases from a string of selects
/// </summary>
/// <param name="select">A string of selects</param>
/// <returns>A string of selects without any aliases</returns>
public static string RemoveAliases(string select)
{
  string[] originalSelect = select.Split(',');
  string[] newSelect = (string[])originalSelect.Clone();
  string alias = " as ";
  for (int i = 0; i < originalSelect.Length; i++)
  {
    int aliasIndex = originalSelect[i].IndexOf(alias, StringComparison.InvariantCultureIgnoreCase);
    if (aliasIndex >= 0)
    {
      string withoutAlias = originalSelect[i].Substring(0, aliasIndex);
      newSelect[i] = withoutAlias;
    }
  }

  StringBuilder sbNoAliases = new StringBuilder();
  for (int i = 0; i < newSelect.Length - 1; i++)
  {
    sbNoAliases.Append(newSelect[i] + ",");
  }
  sbNoAliases.Append(newSelect[newSelect.Length - 1]);

  return sbNoAliases.ToString();
}