3

SQL ステートメントの WHERE 句である文字列を、次のデータが各インデックスの下に保持される 5 つの出力を持つ配列に分割しようとしています。

0 - The initial clauses (WHERE/AND/OR) plus any open brackets. e.g "AND((("
1 - Either the table the first clause comes from or "VALUE" if its a value. e.g. "transactions". 
2 - The field name or value. e.g. "id"
3 - The joining value. e.g. >
4 - Either the table the second clause comes from or "VALUE" if its a value. e.g. "transactions". 
5 - The field name or value. e.g. "id"
6 - Any closing brackets. e.g. ")))"

たとえば、次の文字列をループすると、次の配列が出力されます。

WHERE transactions.status_code= 'AFA 2'
AND (transactions.supp_ref = supplier.supp_ref
AND supplier.supp_addr_ref = address.addr_ref)
OR transactions.user_code = user.user_code

output[0] = "WHERE"
output[1] = "transactions"
output[2] = "status_code"
output[3] = "="
output[4] = "VALUE'
output[5] = "AFA 2"
output[6] = ""

output[0] = "AND("
output[1] = "transactions"
output[2] = "supp_ref"
output[3] = "="
output[4] = "supplier"
output[5] = "supp_ref"
output[6] = ""

output[0] = "AND"
output[1] = "supplier"
output[2] = "supp_addr_ref"
output[3] = "="
output[4] = "address"
output[5] = "addr_ref"
output[6] = ")"

output[0] = "OR"
output[1] = "transactions"
output[2] = "user_code"
output[3] = "="
output[4] = "user"
output[5] = "user_code"
output[6] = ""

SQL ステートメントの残りの部分については、String.Split メソッドを使用して同様の方法で正常に分割しましたが、where 句の違いにより、この部分でこれを行うのが困難です。周りを見回すと、正規表現を使用したほうがよいと思いますが、必要なものがわかりません。どんな助けや指示も大歓迎です。

4

2 に答える 2

0

わかりました、最初に、正規表現はあなたがやろうとしていることに最適ではないかもしれないと思います. そうは言っても、投稿したものを解析し、探しているものに変換する正規表現は次のとおりです。

(?<Group>(?<Concat>where|\s*?\)?\s*?and\s*?\(?|\s*?\)?\s*?or\s*?\(?)(?<TableName>[\w\s]+(?=\.))\.?(?<ColName>.+?(?=\=|like|between|\<\>|\>\=|\<\=|in|\>|\<))\s*?(?<Compare>\=|like|between|\<\>|\>\=|\<\=|in|\>|\<)(?<Value>.*?(?=\s*?and\s*?\(*|or\*?\(*)|.*))

これですべてがカバーされるわけではなく、正規表現パーサーによっては動作が異なる可能性があると確信しています。私は正規表現の作業にThe Regulatorを使用 しています。

これを行うパーサーを作成することをお勧めします。以下にあるものを見てください。このルートに進むことにした場合に役立つかもしれません。そこにある「VALUE」文字列で何をしているのか完全にはわかりませんでしたが、値とtable.colNameを特定したい場合は、これに簡単に追加できます。('a', 'b') のようなものを識別するのは難しくなりますが、それは可能だと思います。

    //A list of chars that we are going to replace with \s"char"\s this list may not be complete.
    // . is not in here. We will take care of that later.
    static string[] specChars = new string[] { "<", ">", "<=", ">=", "=", "like", "in", "between", "or", "and", "(", ")", "where" };
    static string[] delims = new string[] {"and", "or", "where" };
    static string testData = @"WHERE transactions.status_code= 'AFA 2'
    AND (transactions.supp_ref = supplier.supp_ref
    AND supplier.supp_addr_ref = address.addr_ref)
    OR transactions.user_code = user.user_code";
    static void Main(string[] args)
    {
        Print(Parse(testData));
        Console.ReadKey();
    }

    static List<List<string>> Parse(string input)
    {
        List<List<string>> ret = new List<List<string>>();
        //lets remove all the spaces first becaue we are going to put them back
        //the way we want to see them.
        input = input.Replace(" ", "").Replace("\r", "").Replace("\n", "").ToLower();
        foreach (string item in specChars)
        {
            //this will help clean the string so you can use it
            input = input.Replace(item, string.Format(" {0} ", item));   
        }
        string[] splits = input.Split(' ');

        List<string> currList = null;
        foreach (string item in splits.Where(x => x.Length > 0))
        {
            if (delims.Contains(item))
            {
                if (currList != null)
                {
                    ret.Add(currList);
                    currList = new List<string>();
                    currList.Add(item);
                }
                else
                {
                    currList = new List<string>();
                    currList.Add(item);
                }
            }
            else
            {
                if (item.Contains("."))
                {
                    string[] tmp = item.Split('.');
                    currList.Add(tmp[0]);
                    currList.Add(tmp[1]);
                }
                else
                    currList.Add(item);
            }
        }
        if (currList != null)
            ret.Add(currList);
        return ret;
    }

    static void Print(List<List<String>> input)
    {
        StringBuilder sb = new StringBuilder();
        foreach (List<String> item in input)
        {
            sb.Append("New Chunk:\n");
            foreach (string str in item)
            {
                sb.Append(string.Format("\t{0}\n", str));
            }
            sb.Append("\n");
        }

        Console.WriteLine(sb.ToString());
    }
}
于 2013-11-07T14:44:53.973 に答える
0

SQL の解析を検討している場合は、ScriptDom 名前空間を調べることをお勧めします。それはあなたがしようとしていること以上のものかもしれませんが、与えられた SQL クエリに関する詳細を提供する SQL パーサーがいくつかあります。

ここにいくつかのリソースがあります。

MSDN ScriptDOM リファレンス
簡単な紹介

于 2016-11-30T17:33:40.940 に答える