开发者

Converting C# method to quote SQL identifiers to F#

开发者 https://www.devze.com 2022-12-13 17:57 出处:网络
I\'m porting the following method (QuoteIdentifier) from C# to F#. It quotes SQL identifiers (also handling embedded and incorrect quotes).

I'm porting the following method (QuoteIdentifier) from C# to F#. It quotes SQL identifiers (also handling embedded and incorrect quotes).

For example: QuoteIdentifier("dbo.mytable", "[", "]") outputs "[dbo].[mytable]"

Unfor开发者_运维问答tunately, the F# code is even less readable than the C#. Is there a better way to write this in F#?

C# original:

public static string QuoteIdentifier(string id, string quotePrefix, string quoteSuffix) {
    if (String.IsNullOrEmpty(id))
        return id;
    return String.Join(".", SplitIdentifier(id, quotePrefix, quoteSuffix));
}

private static string[] SplitIdentifier(string id, string quotePrefix, string quoteSuffix) {
    if (String.IsNullOrEmpty(id))
        return new string[] { id };
    List<string> list = new List<string>();
    int index = 0;
    do {
        list.Add(GetNextIdentifier(id, quotePrefix, quoteSuffix, ref index));
    } while (index != id.Length);
    return list.ToArray();
}

private static string GetNextIdentifier(string id, string quotePrefix, string quoteSuffix, ref int startIndex) {
    int index = startIndex;
    bool quoted = false;
    StringBuilder builder = new StringBuilder();
    if (!String.IsNullOrEmpty(quotePrefix)) {
        builder.Append(quotePrefix);
        quoted = (String.CompareOrdinal(id, startIndex, quotePrefix, 0, quotePrefix.Length) == 0);
        if (quoted)
            index += quotePrefix.Length;
    }
    for (int i = index; i < id.Length; i++) {
        if (!String.IsNullOrEmpty(quoteSuffix) && String.CompareOrdinal(id, i, quoteSuffix, 0, quoteSuffix.Length) == 0) {
            if ((i + quoteSuffix.Length) == id.Length) {
                index = id.Length;
                break;
            }
            if (id[i + quoteSuffix.Length] == '.') {
                index = (i + quoteSuffix.Length + 1);
                break;
            }
            builder.Append(quoteSuffix).Append(quoteSuffix);
            if (String.CompareOrdinal(id, (i + quoteSuffix.Length), quoteSuffix, 0, quoteSuffix.Length) == 0)
                i++;
        } else {
            index = (i + 1);
            if (!quoted && id[i] == '.')
                break;
            builder.Append(id[i]);
        }
    }
    if (!String.IsNullOrEmpty(quoteSuffix))
        builder.Append(quoteSuffix);
    startIndex = index;
    return builder.ToString();
}

F# rewrite:

[<CompiledName("QuoteIdentifier")>]
let quoteIdentifier id quotePrefix quoteSuffix = 
    let isEmpty = String.IsNullOrEmpty
    let notEmpty = not << isEmpty
    let prefix, suffix = quotePrefix, quoteSuffix
    let equal strA indexA strB = (String.CompareOrdinal(strA, indexA, strB, 0, strB.Length) = 0)
    let getNext start =
        let builder = new StringBuilder()
        let append (s:string) = builder.Append(s) |> ignore
        let quoted = 
            if notEmpty prefix then
                append prefix
                equal id start prefix
            else false
        let index = if quoted then start + prefix.Length else start
        let rec loop i n =
            if i = id.Length then (i, n)
            else
                if notEmpty suffix && equal id i suffix then
                    if (i + suffix.Length) = id.Length then (i, id.Length)
                    elif id.[i + suffix.Length] = '.' then (i, i + suffix.Length + 1)
                    else
                        append suffix
                        append suffix
                        loop (if (equal id (i + suffix.Length) suffix) then i + 2 else i + 1) n
                else
                    if not quoted && id.[i] = '.' then (i, i + 1)
                    else
                        append (id.[i].ToString())
                        loop (i + 1) (i + 1)
        let _, next = loop index index
        if notEmpty suffix then append suffix
        (builder.ToString(), next)
    let split() = 
        0 
        |> Seq.unfold (function 
            | i when i = id.Length -> None 
            | i -> Some (getNext i)) 
        |> Seq.toArray
    if isEmpty id then id
    else String.Join(".", split())


May I suggest a simpler version of the C# code? I can't test it right now, but something like this should work:

public static string QuoteIdentifier(string id, string quotePrefix, string quoteSuffix) {
    if (String.IsNullOrEmpty(id)) {
        return id;
    }
    var identifiers = id.Split(new char[] {'.'}, StringSplitOptions.RemoveEmptyEntries);
    var separator = string.Format("{0}.{1}", quoteSuffix, quotePrefix);
    var quotedString = string.Join(separator, identifiers);
    return string.Format("{0}{1}{2}", quotePrefix, quotedString, quoteSuffix);
}

Once you have this working, you can convert it to a also short F# version.

0

精彩评论

暂无评论...
验证码 换一张
取 消