正規表現に一致する行のサブセットを含むデータビューをすばやく表示します次のことを実行する JSL スクリプトを探しています。
-
アクティブなデータ テーブルで現在選択されている列を取得します。
-
最初に選択された列を取得します。
-
ユーザーに正規表現を入力するよう要求します。
-
その列の値が正規表現と一致するテーブル内の行のみを選択します。
-
一致する行のみを表示するデータ ビュー ウィンドウを開きます。
JSL でこれは可能ですか?
自動化とスクリプトデータアクセスRe: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示する可能です。何を試しましたか?
これは、実装できる(そしておそらく実装すべき)すべてのチェックが欠落している非常に基本的な例です。
Names Default To Here(1);
dt = Current Data Table();
col = (dt << Get Selected Columns("String"))[1]; // I suggest dropping non-character columns
run_expr = Expr(
rgx_pattern = teb << Get Text; // You could check if the pattern is valid regex
dt << Select Where(!Is Missing(Regex(Column(dt, col)[Row()], rgx_pattern)));
// add check if any rows have been selected
dt << Data View; // If linked subset is fine, that is most likely better as it can avoid using select where
dt << Clear Select;
wait(0);
);
nw = New Window("",
H List Box(
Lineup Box(N Col(2),
Text Box("Enter regex pattern"),
teb = Text Edit Box("")
),
Lineup Box(N Col(1),
Button Box("OK",
run_expr
),
Button Box("Cancel")
)
)
);
Write();
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示するうまくいきました。ありがとうございます。
正直に言うと、私の試みはあまり近いものではなく、おそらく AppleScript と Matlab から GUI スクリプトを学習したことから生じた、JSL に関するいくつかの基本的な誤解が露呈したため、コードは含めませんでした。
選択された列名のリストを取得して最初の列名を選択するつもりだったのですが、文字列を返す「ダイアログ表示」関数のようなものを期待していたのですが、どうやらそのような関数は存在しないようで、新しいウィンドウ/リストボックス/ボタン式の構文を強制的に入力させられました。これは私にとってはかなり直感的ではありませんでしたが、今になって仕組みがわかると納得できます。ChatGPTも試してみましたが、全く実行されない長いスクリプトが作成されました。
時間があれば、ソリューションについていくつか質問します。
- 「キャンセル」ボタンが何も反応しないのはなぜでしょうか?Button Box() 呼び出しに2番目の引数がないからだと思いますが、現在のウィンドウを閉じる式は何でしょうか? Close() でしょうか?「Button Box ( "キャンセル" , 近い ())」を試してみましたが、意味不明なエラーが発生してしまいました。あなたのやり方を真似て「ウィンドウを閉じる」を試してみましたが、うまくいったようですが、もっとすっきりとした方法があると思います。
- 「Get Selected Columns()」呼び出しの引数に「String」を指定していますが、ドキュメントによるとこの関数は引数を取らないようです。ここでの「String」とはどういう意味ですか?また、それが受け入れられるとどのように判断したのですか?また、どのような機能を果たすのですか?
- スクリプト実行後すぐに入力を開始したいのですが、フォーカスが正しい位置に移動しません。「nw=...」式の後に「teb << SetFocus;」と入力してみましたが、JMPではテキスト編集ボックスではそのメッセージが理解できないと表示されます。
- Regex で大文字と小文字を区別しないようにすることは可能ですか? 可能であれば、どのようにすればよいですか? (「ドキュメントに従って Regex 引数に " を追加しようとしましたが、エラーが発生します。)
- タブボックスにフォーカスがある状態で、Return/Enter で「Ok」スクリプトをトリガーすることは可能ですか?
- ユーザーが選択した列がない場合は、最初の文字列の列を使用したいのですが、約 20 回試行した後、どの列であるかを判断するのをあきらめました。
- データ ビューのサブセットをリンクしたいのですが、それによってアプローチは変わりますか?
これまでのところ、次のものがあります:
Names Default To Here(1);
run_expr = Expr(
dt = Current Data Table();
selCols = dt << Get Selected Columns("String");
if(N Items(selCols)==0, selCols = dt << get column names("String") );
col = selCols[1];
rgx_pattern = teb << Get Text;
dt << Select Where(!Is Missing(Regex(Column(dt, col)[Row()], rgx_pattern)));
dt << Data View; // I prefer a linked subset, what changes here?
dt << Clear Select;
wait(0);
nw << Close Window;
);
close_expr = Expr(nw << Close Window);
nw = New Window("",
H List Box(
Lineup Box(N Col(2),
Text Box("Enter regex pattern"),
teb = Text Edit Box("", <
<SET width=""></SET>
<P>Big Classを開いてスクリプトを実行し、「ob.+t」と入力したいのですが<ENTER>「2 人のロバートだけを含むデータ ビューを表示します。」今のところ、スクリプトを実行した後、Tab キーを押してから OB.+T キーを押し、Enter キーを 2 回押す必要があるため、これはほぼ不可能です。</ENTER></P>
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示する- できる限り最小限の例を作成したので、キャンセルにはウィンドウを閉じる式は含まれていません。
- 「文字列」が << get column names() と同じように動作するか試してみたところ、うまくいきました。「文字列」値を使わずにテストしてみて、どうなるか(文字列ではなく参照が返されるか)を確認してください。個人的には、列参照を扱うのは大変なので、列名は常に文字列にして、必要に応じて変換しています。ただし、参照(あるいはコロン構文)を使うかどうかは、あなた次第です。
- 複雑な回避策を使用しない限り、タブに固執することになると思います。対話型表示要素 (TextEditBox、Button など) で SetFocus を使用できるようにします。
- ユーザー入力をLowercase()で変換し、列参照をLowercase()で囲むこともできます。あるいは、INGORECASEを使用する場合は、Regex()にデフォルトのキャプチャグループを追加することもできます: 正規表現("ABCD", "d", "\0", IGNORECASE)
- << Set Function を試してみてはいかがでしょうか。これはコミット時にスクリプトを実行し、Enterキーを押すことで実行されます(テキスト編集ボックスの外側をクリックした場合も同様です)。
-
<< Get Column Names(Character, String)[1]
-
r = dt << Get Rows Where(!Is Missing(Regex(Column(dt, col)[Row()], rgx_pattern)));
dt_subset = dt << Subset(Rows(dt), Selected Columns(0), Link to original data table(1));
改善できる点はたくさんありますが、それが何であるかは実際の使用例によって異なります。
編集: サブセットに元のデータテーブル(1)へのリンクを追加しました
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示する素晴らしいです、ありがとうございます!
もう1つ質問があります。複数の列が選択されている場合は、列の値を文字列として連結し、それらに対して正規表現を実行したいと考えています。列が選択されていない場合は、すべての列に対して同じ処理を実行したいと考えています。これは、テーブルに対するegrepの動作を実質的に模倣することになります。これは現実的に実現可能でしょうか?最初の試みについては、以下のコメント行をご覧ください。ただし、選択された列の値だけを取得できないため、まだ実現には至っていません(そして動作しません)。
Names Default To Here( 1 );
run_expr = Expr(
dt = Current Data Table();
selCols = dt << Get Selected Columns( "String" );
If( N Items( selCols ) == 0,
selCols = dt << Get Column Names( "String" )
);
col = selCols[1];
rgx_pattern = teb << Get Text;
dt << Select Where( !Is Missing( Regex( Column( dt, col )[Row()], rgx_pattern, "1", IGNORECASE ) ) );
// dt << Select Where( !Is Missing( Regex( Concat Items( dt << get Rows(Row())," "), rgx_pattern, "1", IGNORECASE ) ) );
dt << Data View;
Wait( 0 );
);
close_expr = Expr( nw << Close Window; Wait( 0 ); );
nw = New Window( "Table Egrep",
H List Box(
lb1 = Lineup Box( N Col( 2 ),
Text Box( "Select column to Enter regex pattern" ),
teb = Text Edit Box( "", Set Script( run_expr ), <
<SET width=""></SET>
<P>ご参考までに、上記の「スクリプトの設定」は「Enter」キーで即座に実行されるようになっており、これはうまく機能します。唯一欠けているのは、上記の動作と、テキスト編集ボックスにフォーカスを移動するために「Tab」キーを押す必要があることです。</P>
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示するある時点で遅くなり始める可能性があり、文字列のみが選択されるようにチェックを追加する必要がありますが、連結を作成するための式を構築できます。
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
dt << Select Columns({:name, :sex});
rgx_patter = "EF";
cols = dt << Get Selected Columns("String");
conc_expr = Expr(Concat());
For Each({colname}, cols,
Insert Into(conc_expr, Name Expr(As Column(dt, colname)));
);
regex_expr = Substitute(
Expr(!Is Missing(Regex(_conc_expr_, _rgx_pattern_, "\0", IGNORECASE))),
Expr(_conc_expr_), Name Expr(conc_expr),
Expr(_rgx_pattern_), rgx_pattern
);
rows_of_interest = dt << Get Rows Where(regex_expr);
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示するモーダル ウィンドウを使用してウィンドウ内にフォーカスを強制することもできますが、ユーザー エクスペリエンスに悪影響を与える可能性があります。
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示するやっと理解し始めたと思ったのに…
ドキュメントにはExpr()は「引数を評価せずに返す」と書いてありますが、正直言って私には全く意味が分かりません。渡された引数をそのまま返すだけのように思えます。
以前のコードではサブルーチンのように見え、当時は意味が通じました。しかし、今はExpr(Concat())と書いてあり、実際に何が連結されているのか分かりません。その後、Expr()オブジェクトにInsert Into()で挿入していますが、JMPはどのようにして値を挿入する場所を把握しているのでしょうか?ChatGPTを使っても、この意味が分かりません。
まるで手の動きを真似してマジシャンのトリックを再現しようとしているような感じで、特に Get Row() のドキュメントではまさに私が実現しようとしている動作が約束されているようなので、イライラします。
もちろん、これはあなたのせいではありません。本当に感謝しています。今あるもので十分だと思います。ありがとうございます!
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示するここでは何も連結されていません。Expr(Concat()) は、式の構築が完了した後に連結される引数のコレクターとして考えることができます。リストを使って式を構築し、そのリストを concat() で置き換えることもできます。
Names Default To Here(1);
dt = open("$SAMPLE_DATA/Big Class.jmp");
val1 = "name";
val2 = "sex";
c = {};
Insert Into(c, Name Expr(As Column(dt, val1)));
Insert Into(c, Name Expr(As Column(dt, val2)));
show(c);
Substitute Into(c, Expr(List()), Expr(Concat()));
Show(c);
// Example use
Eval(EvalExpr(
dt << New Column("Concat", Character, Nominal, Formula(
Expr(Name Expr(c))
));
));
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示するわかりました。このスクリプトは基本的に、unix/linux/mac の「egrep」コマンドの表形式版です。つまり、ユーザーが入力した正規表現 (検索文字列) に一致する行だけを選択/表示します。
Names Default To Here( 1 );
If(
ex = New Window( "Enter search regex",
<
<MODAL></MODAL>
<P>すべてのボタンが正しく機能し、数千行でも十分に高速です。個人的には、アドインを作成してcmd-shift-e(egrep)に連携させ、今では頻繁に使用しています。もちろん、改善点のご提案も歓迎いたします。誰かのお役に立てれば幸いです!</P> <BR /> <P>(そして、忍耐と洞察力を提供してくれた<A href="https://community.jmp.com/t5/user/viewprofilepage/user-id/14366" target="_blank">@jthi</A>に大いに感謝します!)</P>
Re: 正規表現に一致する行のサブセットを含むデータビューをすばやく表示するいいですね!いくつか小さな変更を加えたいと思います。
- 新しいウィンドウを開く前に、テーブルが開いているかどうかを確認し、開いていない場合は stop(); を実行します。
- 一致するものがない場合、最後の行でエラーが発生します。選択された行数を確認し、0の場合はstop()を使用するか、一致するものがなかったという情報をユーザーに表示してください。
- << 行の取得は、<< 選択するよりも速い可能性が高い
- 列参照を評価することで、さらに速度が向上する可能性が高い。
- << On Validateは、最初の正規表現に一致するものがない場合にユーザーに新しい正規表現を入力させたい場合にも使用できます。
もっと見る...
Names Default To Here(1);
If(N Table() == 0,
stop(); // display error message to user if necessary
);
dt = Current Data Table();
nw = New Window("Enter search regex",
<
<MODAL>
0, col = selCols[1]; , col = Column(dt, 1) << get name; ); selrows = Eval(EvalExpr( dt << Get Rows Where(!Is Missing(Regex(Expr(NameExpr(As Column(dt, col))), inputRegex, "1", IGNORECASE))); )); If(N Rows(selrows) == 0, stop(); // display error message if necessary, this could also be done already within modal window (<< On Validate), if you wish to let user perform new search ); dt2 = dt << Subset(Rows(selrows), Selected Columns(0), Link to original data table(1), Output Table("")); // dt2 << Select Rows(1::NRows(dt2)); // to select rows if necessary
</MODAL>