Click here to Skip to main content
15,884,298 members
Please Sign up or sign in to vote.
3.67/5 (2 votes)
See more:
I have a class that accepts the string[] args from the program's main function in its constructor. I would like to be able to create instances using a string as well.

As you may know, it's a little more complicated than just splitting on spaces since space's are valid when preceded and followed by "s. Is there a simple way to reverse engineer this that I'm not thinking of?


C#
static void Main(string[] args)
{

    if (args.length == 0)
    {
        string databasestatement = GetArgsFromDatabase();
        string[] argsfromDB = DOSOMETHING(databasestatement);
        myclass fromDB = new myclass(argsfromDB);
    }
    else
    {
        myclass fromArgs = new myclass(args);
    }

}
Posted
Comments
Sergey Alexandrovich Kryukov 20-May-15 16:01pm    
Why?

I'm asking because I've done some "reverse engineering" of string splitting, but I've done this for the purposes of testing of the command line parsing; and that wasn't exact same behavior, which wasn't so important — the behavior was not the same only when the user incorrectly balances quotation marks. Splitting of the string into arguments becomes non-trivial when there are quotation marks used to pass a string with a blank space inside in a single argument (for example, file name, some text message). What the system does in case of incorrectly balanced quotation is just not quite clear, it looks weird to me (and is not so important).

I would assume that you don't need reverse engineering approach at all. Why, after all, would you store the unparsed command line in your database at all?

—SA
wizardzz 20-May-15 16:44pm    
Sergey,
To recreate tests and recreate bad runs, etc. The database has stored the commandline parameters used by every run in the form of a single string, and it's provided via stored proc as a single string and this isn't likely to change.
This way a failed job can be directly kicked off via our website, pull the commands used by the last run, and use those commands.
It sounds weird, but the short answer is: legacy.
Sergey Alexandrovich Kryukov 20-May-15 16:52pm    
All right. I think Solution 1 is good, I would accept it formally.
—SA
wizardzz 20-May-15 17:06pm    
I will shortly.

1 solution

There's a pretty good implementation by Daniel Earwicker on StackOverflow[^]:
C#
public static string TrimMatchingQuotes(this string input, char quote)
{
    if ((input.Length >= 2) && 
        (input[0] == quote) && (input[input.Length - 1] == quote))
        return input.Substring(1, input.Length - 2);

    return input;
}

public static IEnumerable<string> Split(this string str, Func<char, bool> controller)
{
    int nextPiece = 0;

    for (int c = 0; c < str.Length; c++)
    {
        if (controller(str[c]))
        {
            yield return str.Substring(nextPiece, c - nextPiece);
            nextPiece = c + 1;
        }
    }

    yield return str.Substring(nextPiece);
}

public static IEnumerable<string> SplitCommandLine(string commandLine)
{
    bool inQuotes = false;

    return commandLine.Split(c =>
    {
        if (c == '\"') inQuotes = !inQuotes;
        return !inQuotes && c == ' ';
    })
    .Select(arg => arg.Trim().TrimMatchingQuotes('\"'))
    .Where(arg => !string.IsNullOrEmpty(arg));
}


The same thread also includes the P/Invoke solution[^].
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 20-May-15 16:51pm    
5ed. I have some doubt that the native code perfectly mimic system behavior (I explain the weirdness of this behavior in my comments to the question), but the P/Invoke solution should do it perfectly.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900