外部プログラムのコマンドライン引数を指定する ProcessStartInfo.Arguments は、単なる string 型なので、コマンドラインのエスケープを考慮する必要がある。
エスケープを考慮してくれるプロパティがあってもいい気がするが、エスケープ仕様はプログラム(コンパイラ)依存なので、実装してないのだろう・・・たぶん。
C# コンパイラのエスケープ仕様は下記。
たぶん、大抵の Windows のプログラムは、この仕様に沿ってるはず・・・
(VC++ と java は確認済)
エスケープに関する要点。
[エスケープ+デリミタ付加処理の実装例]
[上記 EncodeCommandLineValue の実行例]
エスケープを考慮してくれるプロパティがあってもいい気がするが、エスケープ仕様はプログラム(コンパイラ)依存なので、実装してないのだろう・・・たぶん。
C# コンパイラのエスケープ仕様は下記。
たぶん、大抵の Windows のプログラムは、この仕様に沿ってるはず・・・
(VC++ と java は確認済)
エスケープに関する要点。
-
スペース/タブが引数の区切り
※コマンドプロンプトでタブを入力したい場合、「cmd /F:OFF」で起動
- 引数がスペース/タブを含む場合、「"」デリミタで囲む
- 「"」リテラルは、「\"」とする
-
「"」直前(デリミタ/リテラル問わず)の「\」リテラルは、「\\」とする
「\」リテラルが複数個の場合は、その分エスケープ(「\」の数が2倍になる)
- 「"」直前でない「\」は、そのままリテラルとして扱われる(エスケープ不要)
[エスケープ+デリミタ付加処理の実装例]
///
/// コマンドライン引数 1 個をエンコード
///
public static string EncodeCommandLineValue(this string value)
{
if( string.IsNullOrEmpty(value) ) return "";
var containsSpace = value.IndexOfAny(new[]{' ', '\t'}) != -1;
// 「\…\"」をエスケープ
// やってることは、「"」直前の「\」の数を 2倍+1
value = _commandLineEscapePattern.Replace(value, @"$1\$&");
// スペース/タブが含まれる場合はデリミタで囲み、末尾が「\」だった場合、エスケープ
if( containsSpace ){
value = "\"" + _lastBackSlashPattern.Replace(value, "$1$1") + "\"";
}
return value;
}
private static readonly Regex _commandLineEscapePattern = new Regex("(\\\\*)\"");
private static readonly Regex _lastBackSlashPattern = new Regex(@"(\\+)$");
///
/// コマンドライン引数複数個をエンコードして、スペースで結合
///
public static string EncodeCommandLineValues(this IEnumerable<string> values)
{
if( values == null ) throw new ArgumentNullException("values");
return string.Join(" ", values.Select(v => EncodeCommandLineValue(v)));
}
[上記 EncodeCommandLineValue の実行例]
value | 戻り値 | |
---|---|---|
通常 | abc | abc |
デリミタ対象 | a bc | "a bc" |
エスケープ対象 | a\b"c\"d | a\b\"c\\\"d |
両方 | a "b" c | "a \"b\" c" |
両方(末尾「\」) | abc \ | "abc \\" |
0 件のコメント:
コメントを投稿