我正在学习正则表达式,而且我正在玩它们。我自己提出了一个练习,其中有一个方法可以删除SQL Select语句中的列别名。这应该是这样的:
到目前为止,我已经创建了两种仅适用于特定情况的方法。以下代码总结了我所做的以及我所面临的问题。
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
答案 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();
}