【问题标题】:How to get all table names with a regex in C#?如何在 C# 中使用正则表达式获取所有表名?
【发布时间】:2012-12-20 09:32:15
【问题描述】:

我需要为 C# 构建一个正则表达式,以便捕获 select 子句中 'from' 关键字之后的所有表名。例如

.
.
.
SELECT field1, field2
FROM table1
WHERE condition1
.
.
.
SELECT field3, field4
FROM table2
WHERE condition2
.
.
.

我尝试读取的文件中有多个 select 子句,并且 select 和 from 之间可以有任何字符(包括换行符、':'、'_' 和任何其他字符)。 我应该如何构造我的正则表达式以获取所有表名?

谢谢

编辑: 我找到了一种获取所有表名的方法。

\s*SELECT[^;]*FROM\s*(?<key>[^\n]*)

这可能会在某一天对某人有所帮助。 谢谢

【问题讨论】:

  • 当我尝试SELECT[\D|\d]*FROM (?&lt;key&gt;[^ \n]*) 时,它会找到一个从第一个选择开始一直到最后一个选择的匹配项。相反,我希望它匹配所有选择并返回它们的所有表名。
  • 试试这个网站,在找出 RegExes 时总是能帮助我regexpal.com
  • @Charleh 用于 Javascript 正则表达式。对于 .NET,您应该使用 RegexHero
  • 你不应该尝试,因为这太复杂了。派生表、CTE、EXISTS 子句、CROSS APPLY 等等呢?提交估计执行计划的查询并挖掘结果数据。
  • @ErikE 你能举个简单的例子吗?

标签: c# sql regex


【解决方案1】:

除非所有查询都只有一个表,并且 cmets 没有什么有趣的事情,否则使用正则表达式是一个失败的提议。而是:

SET SHOWPLAN_ALL ON;

--All your queries here

请参阅set showplan_all docs。

当我说正则表达式会变得复杂时,这就是我的意思。这些只是部分的考虑:

  • 您必须检测引用字符串的开头:"、' 和 [,并忽略其中的所有字符,直到正确终止。如果结束字符加倍,则不要终止(即'this is ''fun'', he said' 不会在is 之后停止)。

  • 您必须排除不在引号内的单行 cmets --,并在下一个 CRLF 处终止它们。 cmets 中的引号不会像往常一样以字符串开头。

  • 您必须排除不在引号内或单行注释内的多行 cmets(以 /* 开头),然后跳过除终止符 @987654330 之外的所有其他内容@。在您的正则表达式中,请务必使用反斜杠 \ 转义 * 字符。

  • 然后您必须找到有效的FROM 子句,并具有正确的字边界(例如,列名SelfRom 或AfroMonkey 上没有错误匹配)。

  • 1234563由于 SQL 查询不需要有分号终止符;,那么您还必须在SELECT、DBCC、SET、CREATE、ALTER、DROP 等处终止等等。
  • 但即使是前两点本身也不够,因为如果您的查询如下所示:

    SELECT *
    FROM
       MyTable T
       INNER JOIN (
          SELECT * FROM YourTable Y WHERE Active = 1
       ) X ON T.ID = Y.ID
       INNER JOIN AnotherTable A
          ON X.AID = A.AID
    

    现在您必须解析括号,并且在看到任何这些关键字时不要停止捕获 FROM 子句。而且你必须跟踪你有多少括号,并一直忽略,直到你有那么多括号。最后,您将如何处理这些,因为派生表就像一个表——您想要派生表的全​​文还是只需要其中的表?

要做到这一切,您不能只从文本中的第一个有效FROM 开始匹配,因为这可能在引号或 cmets 内。您必须匹配从头开始的所有文本,因为这是使用正则表达式确保您找不到不应该匹配的唯一方法。

这是我想出的,只是试图处理 cmets。甚至没有引号。它只能找到 from 子句,而不是它里面的内容。另外,我们必须防止括号被捕获,这样我们在检查捕获组以获取实际的 FROM 子句时就不会一团糟。

(?:(?:-(?!-)|/(?!\*)|f(?!rom)|[^-f/])|--[^\n]*\n|/\*(?:\*/)*\*/)*from()

而且它可能充满了错误,一旦我玩了一点,我就不得不重新考虑整个事情,总而言之,这将是巨大的时间浪费。

我认为你低估了要做好这样的事情的难度。但是有一个完全可靠的解决方案!我在上面给出的那个:让 SQL Server 为您解析所有内容。您可以轻松解析返回的计划,因为它的结构很简单。

【讨论】:

    【解决方案2】:

    首先我想说看看这个教程:http://www.codeproject.com/Articles/9099/The-30-Minute-Regex-Tutorial

    查看这样的正则表达式:((?&lt;=FROM )[^\s]+)

    此正则表达式将在"FROM "(包括空格)之后直接开始读取,并在第一个空格(^\s) 处停止读取

    如果你尝试这样的事情

    foreach (Match m in Regex.Matches(input, @"((?<=FROM )[^\s]+)")
    {
        string output = m.Value;
    }
    

    编辑:

    我不是 100% 确定这个正则表达式。如果您的名称末尾有换行符,这可能会做得更好:@"((?&lt;=FROM)[^\n]+)) 但您可能应该修剪输出,因为输出字符串的开头可能有一个空格。

    【讨论】:

    • 表格!==来自我亲爱的小伙子
    【解决方案3】:
    var input = "select name from Table1 where id =2";
    var pattern = @"from\s*(.*?)\s*where"; // where car= is the first delimiter and ; is the second one
    var result = Regex.Match(input, pattern).Groups[1].Value;
    MessageBox.Show(result);
    

    【讨论】:

    • 那么说“来自”的 cmets 呢?灾难。
    • 多个查询一起处理将无法正确处理——结果将跨越所有查询。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-07
    • 2010-11-25
    • 2013-03-24
    • 2016-08-29
    • 1970-01-01
    • 2018-08-31
    • 1970-01-01
    相关资源
    最近更新 更多