正しいアイデアを思いついた @mp3ferret のおかげです。しかし、 を使用したソリューションの例がなかったEnvironment.CommandLine
ので、先に進んで、OriginalCommandLine
最初に入力したコマンド ライン引数を取得するクラスを作成しました。
引数はtokenizer
、任意のタイプの文字の二重引用符で囲まれた文字列、または非空白文字の引用符で囲まれていない文字列として正規表現で定義されます。引用文字列内では、引用文字をバックスラッシュでエスケープできます。 ただし、末尾のバックスラッシュとそれに続く二重引用符、および空白はエスケープされません。
空白によるエスケープの例外を選択した理由は、バックスラッシュで終わる引用パスに対応するためでした。エスケープされた二重引用符が実際に必要になる状況に遭遇する可能性ははるかに低いと思います。
コード
static public class OriginalCommandLine
{
static Regex tokenizer = new Regex(@"""(?:\\""(?!\s)|[^""])*""|[^\s]+");
static Regex unescaper = new Regex(@"\\("")(?!\s|$)");
static Regex unquoter = new Regex(@"^\s*""|""\s*$");
static Regex quoteTester = new Regex(@"^\s*""(?:\\""|[^""])*""\s*$");
static public string[] Parse(string commandLine = null)
{
return tokenizer.Matches(commandLine ?? Environment.CommandLine).Cast<Match>()
.Skip(1).Select(m => unescaper.Replace(m.Value, @"""")).ToArray();
}
static public string UnQuote(string text)
{
return (IsQuoted(text)) ? unquoter.Replace(text, "") : text;
}
static public bool IsQuoted(string text)
{
return text != null && quoteTester.Match(text).Success;
}
}
結果
以下の結果からわかるように、上記のメソッドの修正は引用符を維持しながら、遭遇する可能性のある現実的なシナリオをより適切に処理します。
Test:
ConsoleApp1.exe foo1 notepad.exe "C:\Progra\"m Files\MyDocuments\" "C:\Program Files\bar.txt"
args[]:
[0]: foo1
[1]: notepad.exe
[2]: C:\Progra"m Files\MyDocuments" C:\Program
[3]: Files\bar.txt
CommandLine.Parse():
[0]: foo1
[1]: notepad.exe
[2]: "C:\Progra"m Files\MyDocuments\"
[3]: "C:\Program Files\bar.txt"
ついに
二重引用符をエスケープするための代替スキームを使用して議論しました。""
コマンドラインがバックスラッシュを頻繁に扱うことを考えると、使用する方が良いと思います。コマンドライン引数が通常処理される方法と下位互換性があるため、バックスラッシュのエスケープ方法を維持しました。
そのスキームを使用する場合は、正規表現に次の変更を加えます。
static Regex tokenizer = new Regex(@"""(?:""""|[^""])*""|[^\s]+");
static Regex unescaper = new Regex(@"""""");
static Regex unquoter = new Regex(@"^\s*""|""\s*$");
static Regex quoteTester = new Regex(@"^\s*""(?:""""|[^""])*""\s*$");
args
引用符をそのままにして、期待するものに近づけたい場合は、2 つの正規表現を変更してください。まだ小さな違いがありますが、私のソリューションから 返され"abc"d
ます。abcd
args
[0] = "abc", [1] = d
static Regex tokenizer = new Regex(@"""(?:\\""|[^""])*""|[^\s]+");
static Regex unescaper = new Regex(@"\\("")");
本当にと同じ数の要素を取得したい場合はargs
、次を使用します。
static Regex tokenizer = new Regex(@"(?:[^\s""]*""(?:\\""|[^""])*"")+|[^\s]+");
static Regex unescaper = new Regex(@"\\("")");
完全一致の結果
Test: "zzz"zz"Zzz" asdasd zz"zzz" "zzz"
args OriginalCommandLine
------------- -------------------
[0]: zzzzzZzz [0]: "zzz"zz"Zzz"
[1]: asdasd [1]: asdasd
[2]: zzzzz [2]: zz"zzz"
[3]: zzz [3]: "zzz"