Mel -comandフラグなどのダブルクォーテーションの克服方法

クリーク・アンド・リバー社 COYOTE CG STUDIO テクニカルチームのグレてしまったのが納得できる武将は前田(慶次)利益、戦国大好き人間の中林です。

Melで""に囲まれた命令を使う場合があります。
主にUI系の-comandフラグに使われています。
こちらはMayaの公式リファレンスのbuttonコマンドのMel例です。

window -width 150;
columnLayout -adjustableColumn true;
    button -label "Button 1" -command "defaultButtonPush";
showWindow;
proc defaultButtonPush()
{
    print "Button 1 was pushed.\n";
}

これはボタンを押す度に「Button 1 was pushed.(改行)」をしています。上記のスクリプトでプロシージャを分けないでprintをできますか?
僕はこの方法に苦手意識を持っていてます。なぜならダブルクォーテーションを多重で使うからです。多重で使う場合は"コマンド \"文字列\" "の¥マークの使い方が複雑だからです。
これなら、まだマシですがここに変数を使おうとすると複雑すぎてグローバル変数に渡したほうが早いのでは思います。
しかし、とある裏技を見つけてからは処理への苦手意識が少し(いや、ちょっと)克服できました。

初歩的なソースのクイズ

button -label "Button 1" -command "print "Button 1 was pushed.\n"";
➁ button -label "Button 1" -command "print \"Button 1 was pushed.\n\"";
➂ button -label "Button 1" -command "print \"Button 1 was pushed.\\n\"";
➃ button -label "Button 1" -command "print \"Button 1 was pushed.\\n\";";

これはMel例をプロシージャを使わないで実行をする場合のbutton文の正解は何番でしょうか?
こちらは1行ずつコピーして試してみると分かります。
ただし、正解が分かるまで何回もコンパイルをしてメニューボタンをクリックするのは大変です。

printコマンドを使うと正解が分かる!!

Mel例のプロシージャ内を改めて見ると、今回の目標とするコマンドはprint "Button 1 was pushed.\n";です。
では➀から-command後の””に囲まれた部分をスクリプトエディタでprintコマンドで試してみましょう。

print("print "Button 1 was pushed.\n"");
// エラー: print("print "Button 1 was pushed.\n""); //
// エラー: Line 1.20: Syntax error //

そもそも、エラーで実行できません。

print("print \"Button 1 was pushed.\n\"");
print "Button 1 was pushed.
"

良くわからないところで改行して、ひとつ下の行にダブルクォーテーションが表示されてます。これは改行の\nが失敗しているからです。

print("print \"Button 1 was pushed.\\n\"");
print "Button 1 was pushed.\n"
print("print \"Button 1 was pushed.\\n\";");
print "Button 1 was pushed.\n";

➂、➃は結果は余計なダブルクォーテーションが消えて見た目がプロシージャ内の答えと一緒になっていることが分かります。最後の改行のセミコロンが必要かはケースバイケースですね。
なので、逆に考えるとprintコマンドを実行して、自分の理想通りのコマンドが表示されれば正解になります。いきなり-commandフラグの後ろにソースを書くと混乱をしますが、printコマンドで理想のコマンドを組んでから移植をすると凄く楽になります。

変数を渡してみよう初級編

ここではプロシージャを少し変更して変数を渡す実験をしましょう。

proc defaultButtonPush(string $str)
{
    print ($str + " was pushed.\n");
}

ここで理想的なコマンドはdefaultButtonPush("Button 1");だと思います。
これをprintコマンドで理想になるように実行するとこうなります。

print("defaultButtonPush(\"Button 1\");");
defaultButtonPush("Button 1");

理想が分かれば後はコピーをするだけです。

button -label "Button 1" -command ("defaultButtonPush(\"Button 1\");");

これで確実な内容のコマンドを用意することができます。
これは渡した先のみが変数なので、分かりやすいです。

変数を渡してみよう中級編

それでは中級編では渡す元も変数にした場合をクイズ形式で出します。理想的なコマンドはdefaultButtonPush("Button 1");です。

string $button = "Button 1";
➀ print ("defaultButtonPush(" + $button + ");");
➁ print ("defaultButtonPush(\" + $button + \");");
➂ print ("defaultButtonPush(\"" + $button + "\");");
➃ print "defaultButtonPush(\"" + $button + "\");";

確認しやすいように今回は初めからprintコマンドで出題してます。
それぞれをスクリプトエディタで試してみましょう。

print ("defaultButtonPush(" + $button + ");");
defaultButtonPush(Button 1);

一見、正しそうだけど「Button 1」がダブルクォーテーションで囲まれていません。

print ("defaultButtonPush(\" + $button + \");");
defaultButtonPush(" + $button + ");

これは変数のままダブルクォーテーションで囲まれています。
これだと最終結果が「 + $button + was pushed.」という文字列になります。

print ("defaultButtonPush(\"" + $button + "\");");
defaultButtonPush("Button 1");

➂が正解です。まさに理想通りの結果なので-commandフラグの後ろにコピぺして完成です。

print "defaultButtonPush(\"" + $button + "\");";
// エラー: print "defaultButtonPush(\"" + $button + "\");"; // 
// エラー: Line 1.30: Syntax error // 

エラーで実行できません。これはMel以外のプログラムを使っている人によっては何でと思いますが、Mel独自の仕様で文字列と変数を結合する場合は()で囲う必要があります。
()で囲わないと1つの式として扱ってくれません。
この()の内容は見落としやすく、printコマンドで確認せずに実行するとハマる原因になります。

変数を渡してみよう上級編

printを細かく確認をしていけば、かなり長い命令文も結合することができます。

string $cmd;
string $text = "name change Button ";
global int $i = 1;
int $bCunt = true;    // falseにするとボタンの名前が変わらない

$cmd = "global int $i;";
if($bCunt){
    $cmd += "$i++;";
    $cmd += "if($i > 5)$i=1;";
} else {
    $text = "not " + $text;
} 
$cmd += "print (\"" + $text + "\" + $i + \".\\n\");";
$cmd += "button -e -l (\"Button \" + $i) Btn01;";
print ($cmd + "\n");

window -width 150;
columnLayout -adjustableColumn true;
    button -label "Button 1" -command $cmd Btn01;
showWindow;

こちらは試して貰うと分かりますが押すたびにボタン名が1~5の変更を繰り返します。更に$bCuntをfalseに変えるとボタンの変更がなくなります。
これは試しに作りましたが、常にprintコマンドで理想形になるかチェックしながら作りました。
これはあくまでこんな事もできるという一例なので、普段の僕ならこんな面倒くさい命令は素直に別プロシージャで作ります。ただ、ダブルクォーテーションでのコマンドが苦手だった僕もこの裏技を使えば少し複雑なことができるようになります。
このprintで確認はMel以外にもPythonや多言語でも応用は効くので、コメント内で命令を作るのが苦手な人は試してみてください。

Author: 中林 伸和